在函數內部有着一個名叫arguments的類數組對象,內部包含着傳入函數的全部參數,在arguments對象中,有一個名叫callee的屬性,其做用可見下面這個階乘的栗子:javascript
function factorial(num){ if(num<=1){ return 1; }else{ return num*factorial(num-1); //這裏也能夠寫成以下方式 return num*arguments.callee(num-1); } } console.log(factorial(5))//120
能夠看到的是,arguments.callee這個屬性做爲一個指針指向了擁有arguments對象的函數,也能夠認爲是當前正在執行的函數,並且能夠消除與函數名factorial的耦合,不過值得注意的是,在ES5的嚴格模式下,調用arguments.callee方法會報錯。java
函數內部還有一個對象,就是咱們所熟悉的this對象,this對象引用的是函數執行的環境對象,簡單來講,this老是指向函數的直接調用者,而非間接調用者,在對象中,若是有new關鍵字,this指向new出來的那個對象。數組
在函數對象中,有個屬性名爲caller,這個屬性做爲一個引用,保存着調用當前函數的其餘函數的引用,以下app
(function(){ bar();//function (){bar();} })(); function bar(){ console.log(bar.caller)//arguments.callee.caller }
能夠看到的是,匿名函數內部調用了bar函數,在bar函數內部,由於 bar.calller指向了調用bar的匿名函數,因此執行bar.caller就等於匿名函數的源代碼,同callee同樣的是,在ES5中訪問caller屬性會報錯。函數
函數內部除了以上容易混淆的屬性之外,還有些方法有時候也會讓人比較困惑,例如call跟apply,show the codethis
function add(a,b){ return a+b; } function foo(a,b){ console.log(add.call(this,a,b)) } function bar(a,b){ console.log(add.apply(this,[a,b])) } foo(20,20)//40 bar(20,20)//40
能夠看到的是,call和apply兩個方法做用都是在特定的做用域上面調用函數,換句話說,就是改變函數體內this指向,在foo和bar函數中,咱們利用call和apply將函數的this值綁定到add函數上,所以它們即可以對內部的參數執行add函數裏面的加法操做。指針
call和apply方法大做用致相同,不一樣的方法接受的參數,call必需要明確全部要處理的參數,也就是說,參數必需要逐個列舉,而apply方法能夠選擇數組做爲參數,所以能夠在具體的環境中,看看是選擇call仍是apply方法。code