人們對於this的綁定常常有兩個誤解,一:指向函數本身,二:指向函數作用域。這兩種想法都是錯的,this並不指向函數本身,也不指向函數作用域。 因為this不指向函數本身,所以foo.count的值依然是0。 因為this不指向函數作用域,所以輸出的是2。 this實際上是在函數被調用時發生的綁定, ...
人們對於this的綁定常常有兩個誤解,一:指向函數本身,二:指向函數作用域。這兩種想法都是錯的,this並不指向函數本身,也不指向函數作用域。
function foo(){ this.count++; } foo.count = 0; for(var i = 0 ; i<5 ; i++){ foo(); } alert( foo.count ); // 0
因為this不指向函數本身,所以foo.count的值依然是0。
function foo(){ var a = 1 ; alert(this.a); } var a = 2; foo(); // 2
因為this不指向函數作用域,所以輸出的是2。
this實際上是在函數被調用時發生的綁定,它指向什麼完全取決於函數在哪裡被調用。
this的綁定一共有四種綁定:1:預設綁定(即沒有明確的調用對象)
2:隱性綁定(即作為對象方法調用,this會被綁定到該對象)
3:顯性綁定(使用apply()和call()調用,兩個方法的第一個參數為一個對象,this被綁定到該對象)
4:new綁定(使用new來調用函數,會構造一個新對象,並且把this綁定到該對象)
一:預設綁定 (即沒有明確的調用對象)
function foo(){ var a = 1 ; alert(this.a); } var a = 2; foo(); // 2 (非嚴格模式下)
沒有明確調用對象,this會被綁定到window對象,所以this.a就是window.a,即為2。不過這得在非嚴格模式下,只有在非嚴格模式下this才會被綁定到window對象,而在嚴格模式下,this被綁定到undefined。
二:隱性綁定 (即作為對象方法調用,this會被綁定到該對象)
function foo(){ var a = 1; alert(this.a); } var obj = { a:2, foo:foo }; obj.foo(); // 2
obj對象調用foo()函數,this被綁定到obj對象,所以輸出了obj對象的a的值2。
對象屬性引用鏈中只有最後一層會影響調用位置
function foo(){ alert(this.a); } var obj2 = { a:2, foo:foo }; var obj1 = { a:1, obj2:obj2 }; obj1.obj2.foo(); //2
obj1和obj2兩個對象連續調用,this會被綁定到最後一個對象,即obj2,所以輸出2
隱式丟失:被隱式綁定的函數會丟失綁定對象,有兩種情況會丟失,一種為引用,另一種為回調函數。
引用:
function foo(){ alert(this.a); } var obj = { a:1, foo:foo }; var bar = obj.foo; var a = "global 1"; bar(); //global 1
bar是obj.foo的一個引用,實際上它引用的是foo函數本身,所以this被綁定到window對象,輸出的是"global 1"
回調函數:
function foo(){ alert(this.a); } function doFoo(fn){ fn(); } var obj = { a = 1, foo:foo } var a = "global 1"; doFoo(obj.foo); //"global 1"
調用回調函數的函數可能會修改this
三:顯性綁定(使用apply()和call()調用,兩個方法的第一個參數為一個對象,this被綁定到該對象)
function foo(){ alert(this.a); } var obj = { a:1 }; foo.call(obj); // 1
call()的參數若為空,預設調用window對象,若為一個原始值(字元串類型,布爾類型或者數字類型),則這個原始值會被轉換成它的對象形式(new String(),new Boolean() 或者 new Number()),這被稱為“裝箱”
硬綁定———顯示綁定的一種變形
優點:可以解決丟失綁定問題
缺點:硬綁定後不可能再修改它的this
function foo(){ alert(this.a); } var obj = { a:2 }; var bar = function(){ foo.call(obj); }; bar(); // 2 setTimeout(bar,100); // 2 bar.call(window); // 2
ES5中提供了內置方法Function.prototype.bind
function foo(something){ alert(this.a, something); return this.a + something; } var obj = { a:2 }; var bar = foo.bind(obj); var b = bar(3); // 2 3 alert(b); // 5
bind()會返回一個硬編碼的新函數,它會把參數設置為this的上下文並調用原始函數
四:new綁定(使用new來調用函數,會構造一個新對象,並且把this綁定到該對象)
function foo(a){ this.a = a; } var bar = new foo(2); alert(bar.a); // 2
this綁定的四條規則的優先順序: new綁定 > 顯示綁定 > 隱式綁定 > 預設綁定