一張圖,先捋一捋邏輯
arguments
在函數內部,有兩個特殊的對象:arguments 和 this。arguments是一個類數組對象,包含着傳入函數中的所有參數。在函數體內可以通過arguments對象來訪問這個參數數組,從而獲取傳遞給函數的每一個參數。
arguments對象只是與數組類似(它不是Array的實例)。可以使用方括號語法訪問它的每個元素。
arguments[0]
沒有傳遞值的命名參數將自動被賦予 undefined 值。這就跟定義了變量但又沒有初始化一樣。
arguments.callee
這個arguments對象還有一個明教callee的屬性,該屬性是一個指針,指向擁有這個arguments對象的函數。
一個使用arguments.callee
的例子。
function factorial(num){
if (num <=1) {
return 1;
} else {
return num * factorial(num-1)
}
}
定義階乘函數一般都要用到遞歸算法;,在函數有名字,而且名字以後也不會變的情況下,這樣定義沒有問題。但問題是這個函數的執行與函數名 factorial耦合在了一起。爲了消除這種緊密耦合的現象,可以像下面這樣使用 arguments.callee。
function factorial(num){
if (num <=1) {
return 1;
} else {
return num * arguments.callee(num-1)
}
}
在這個重寫後的 factorial()函數的函數體內,沒有再引用函數名factorial。這樣,無論引用函數時使用的是什麼名字,都可以保證正常完成遞歸調用。
caller
ECMAScript 5 也規範化了另一個函數對象的屬性:caller。除了 Opera 的早期版本不支持,其他瀏覽器都支持這個ECMAScript3並沒有定義的屬性。這個屬性中保存着調用當前函數的函數的引用,如果是在全局作用域中調用當前函數,它的值爲 null
function outer(){
inner();
}
function inner(){
alert(inner.caller);
}
outer();
上面代碼會導致警告框中顯示 outer()函數的源代碼。因爲 outer()調用了 inter(),所以 inner.caller 就指向 outer()。爲了降低耦合度,也可以通過 arguments.callee.caller 來訪問相同的信息
function outer(){
inner();
}
function inner(){
alert(arguments.callee.caller);
}
outer();
IE、Firefox、Chrome 和 Safari 的所有版本以及 Opera 9.6 都支持 caller 屬性。
當函數在嚴格模式下運行時,訪問 arguments.callee 會導致錯誤。ECMAScript 5 還定義了 arguments.caller 屬性,但在嚴格模式下訪問它也會導致錯誤,而在非嚴格模式下這個屬性始終是 undefined。定義這個屬性是爲了分清 arguments.caller 和函數的 caller 屬性。以上變化都是爲 了加強這門語言的安全性,這樣第三方代碼就不能在相同的環境裏窺視其他代碼了。 嚴格模式還有一個限制:不能爲函數的 caller 屬性賦值,否則會導致錯誤。
老生常談this的問題
- 全局代碼中的this指向 window
- 單純的函數調用,this指向全局對象,window
- 作爲對象的方法被調用時候指向調用調用他的對象。
- new 聲明構造函數的時候,this指向這個新創建的對象。
- 在內部函數中,仍然指向全局對象winodw
- 可以用call,apply,bind改變this的指向。
new操作符幹了什麼?
- 創建一個新對象;[var o = {};]
- 將構造函數的作用域賦給新對象(因此this指向了這個新對象)
- 執行構造函數中的代碼(爲這個新對象添加屬性);
- 返回新對象。
留下箭頭函數的問題。
此文結合上面腦圖看效果更佳。