this全面解析
調(diào)用位置
在理解 this 的綁定過程之前,首先要理解調(diào)用位置:調(diào)用位置就是函數(shù)在代碼中被調(diào)用的位置(而不是聲明的位置)。函數(shù)調(diào)用位置的不同會造成 this 綁定對象的不同
最重要的是要分析調(diào)用棧(就是為了到達當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù))筒占。我們關(guān)心的調(diào)用位置就在當(dāng)前正在執(zhí)行的函數(shù)的前一個調(diào)用中。
function baz() {
// 當(dāng)前調(diào)用棧是:baz
// 因此魄健,當(dāng)前調(diào)用位置是全局作用域
console.log( "baz" );
bar(); // <-- bar 的調(diào)用位置
}
function bar() {
// 當(dāng)前調(diào)用棧是 baz -> bar
// 因此赋铝,當(dāng)前調(diào)用位置在 baz 中
console.log( "bar" );
foo(); // <-- foo 的調(diào)用位置
}
function foo() {
// 當(dāng)前調(diào)用棧是 baz -> bar -> foo
// 因此插勤,當(dāng)前調(diào)用位置在 bar 中
console.log( "foo" );
}
baz(); // <-- baz 的調(diào)用位置
調(diào)用規(guī)則
? ?1.默認(rèn)綁定
? ? ? ? 獨立函數(shù)調(diào)用沽瘦。可以把這條規(guī)則看作是無法應(yīng)用
? ? ? ? function foo() {
? ? ? ? ? ?console.log( this.a );
? ? ? ? ?}
? ? ? ? ?var a = 2;
? ? ? ? ?foo(); // 2
? ? 2.隱式綁定
? ? ? ? 對象屬性引用鏈中只有最頂層或者說最后一層會影響調(diào)用位置农尖。
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
隱式丟失
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函數(shù)別名析恋!
var a = "oops, global"; // a 是全局對象的屬性
bar(); // "oops, global"?
雖然 bar 是 obj.foo 的一個引用,但是實際上盛卡,它引用的是 foo 函數(shù)本身助隧,因此此時的bar() 其實是一個不帶任何修飾的函數(shù)調(diào)用,因此應(yīng)用了默認(rèn)綁定滑沧。
3.顯式綁定
function foo() {
console.log( this.a );
}
var obj = {
a:2
};
foo.call( obj ); // 2
? ? 硬綁定
? ? API調(diào)用的“上下文”
? ? 都是用CALL APPLY;
4 .new綁定
? ?用 new 來調(diào)用并村,這種函數(shù)調(diào)用被稱為構(gòu)造函數(shù)調(diào)用
? ?使用 new 來調(diào)用函數(shù),或者說發(fā)生構(gòu)造函數(shù)調(diào)用時滓技,會自動執(zhí)行下面的操作哩牍。
1. 創(chuàng)建(或者說構(gòu)造)一個全新的對象。
2. 這個新對象會被執(zhí)行 [[ 原型 ]] 連接令漂。
3. 這個新對象會綁定到函數(shù)調(diào)用的 this膝昆。
4. 如果函數(shù)沒有返回其他對象丸边,那么 new 表達式中的函數(shù)調(diào)用會自動返回這個新對象。
優(yōu)先級
1. 函數(shù)是否在 new 中調(diào)用(new 綁定)荚孵?如果是的話 this 綁定的是新創(chuàng)建的對象妹窖。
? ? var bar = new foo()
2. 函數(shù)是否通過 call、apply(顯式綁定)或者硬綁定調(diào)用收叶?如果是的話骄呼,this 綁定的是指定的對象。
var bar = foo.call(obj2)
3. 函數(shù)是否在某個上下文對象中調(diào)用(隱式綁定)判没?如果是的話谒麦,this 綁定的是那個上下文對象。
var bar = obj1.foo()
4. 如果都不是的話哆致,使用默認(rèn)綁定绕德。如果在嚴(yán)格模式下,就綁定到 undefined摊阀,否則綁定到全局對象耻蛇。
var bar = foo()
被忽略的this
如果你把 null 或者 undefined 作為 this 的綁定對象傳入 call、apply 或者 bind
箭頭函數(shù)
1. 只使用詞法作用域并完全拋棄錯誤 this 風(fēng)格的代碼胞此;
2. 完全采用 this 風(fēng)格臣咖,在必要時使用 bind(..),盡量避免使用 self = this 和箭頭函數(shù)漱牵。