看下面這個例子
function foo(num) {
console.log( "foo: " + num );
// 追蹤 `foo` 被調(diào)用了多少次
this.count++;
}
foo.count = 0;
var i;
for (i=0; i<10; i++) {
if (i > 5) {
foo( i );
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// `foo` 被調(diào)用了多少次?
console.log( foo.count ); // 0
第一種解決方案:創(chuàng)建另一種對象來持有count屬性。但這種方法直接忽略了this,采用了詞法作用域。
第二種解決方案: 強迫this指向foo
this 實際上是在函數(shù)被調(diào)用時建立的一個綁定,它指向 什么 是完全由函數(shù)被調(diào)用的調(diào)用點來決定的。
一。綁定規(guī)則優(yōu)先級
function foo() {
console.log( this.a );
}
var obj1 = {
a: 2,
foo: foo
};
var obj2 = {
a: 3,
foo: foo
};
obj1.foo(); // 2
obj2.foo(); // 3
obj1.foo.call( obj2 ); // 3
obj2.foo.call( obj1 ); // 2
明確綁定>隱含綁定
function foo(something) {
this.a = something;
}
var obj1 = {
foo: foo
};
var obj2 = {};
obj1.foo( 2 );
console.log( obj1.a ); // 2
obj1.foo.call( obj2, 3 );
console.log( obj2.a ); // 3
var bar = new obj1.foo( 4 );
console.log( obj1.a ); // 2
console.log( bar.a ); // 4
new綁定>隱含綁定
function foo(something) {
this.a = something;
}
var obj1 = {};
var bar = foo.bind( obj1 );
bar( 2 );
console.log( obj1.a ); // 2
var baz = new bar( 3 );
console.log( obj1.a ); // 2
console.log( baz.a ); // 3
硬綁定>new綁定
二。判定this
1.函數(shù)是通過 new 被調(diào)用的嗎(new 綁定)?如果是,this 就是新構(gòu)建的對象。
var bar = new foo()
2.函數(shù)是通過 call 或 apply 被調(diào)用(明確綁定),甚至是隱藏在 bind 硬綁定 之中嗎?如果是,this 就是那個被明確指定的對象。
var bar = foo.call( obj2 )
3.函數(shù)是通過環(huán)境對象(也稱為擁有者或容器對象)被調(diào)用的嗎(隱含綁定)?如果是,this 就是那個環(huán)境對象。
var bar = obj1.foo()
否則,使用默認(rèn)的 this(默認(rèn)綁定)。如果在 strict mode 下,就是 undefined,否則是 global 對象。
var bar = foo()
注意:對于數(shù)組遍歷方法(forEach,map,find,,,)如果使用的是普通匿名函數(shù)的方式,則其中的this始終是windows。若要改變指向,使用bind()。
三。箭頭函數(shù)中的this
function foo() {
// 返回一個箭頭函數(shù)
return (a) => {
// 這里的 `this` 是詞法上從 `foo()` 采用的
console.log( this.a );
};
}
var obj1 = {
a: 2
};
var obj2 = {
a: 3
};
var bar = foo.call( obj1 );
bar.call( obj2 ); // 2, 不是3!
箭頭函數(shù)中的this不會被覆蓋,由外部環(huán)境覺得this的指向。