this
首先我們分析一下下面代碼的執行結果
function foo(num) {
console.log( "foo: " + num );
this.count++; //記錄函數執行次數
}
foo.count = 0;
function test(){
for(let i = 0 ; i < 4; i++){
foo(i)
}
console.log('foo執行次數:'+foo.count)
}
test()
執行結果如下:
foo: 0
foo: 1
foo: 2
foo: 3
foo執行次數:0
由此可見this指向的並不是函數自身
。this 是在運行時進行綁定的,它的指向取決於它的調用位置
。我們可以通過分析調用棧
來找到函數的調用位置。(調用位置爲當前正在執行的函數的前一個調用中)。當我們在第一個例子中增加debugger
,在瀏覽器工具中可以清晰的看到函數的調用棧:
foo函數的調用位置在test函數中,此時this的指向默認綁定
爲window,而不是foo對象。我們可以可以通過修改this.count
爲foo.count
來達到目的。
綁定
this的綁定規則有:默認綁定、隱式綁定、顯式綁定、new綁定,上面函數調用中this就是默認綁定。
new綁定
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); //2
var bar2 = new foo(3);
console.log(bar2.a) //3
當使用new調用foo函數時,會構造一個新對象並把它綁定到 foo
顯式綁定
我們可以通過call、bind、apply來改變this的指向。call、apply本質上沒有區別,都是立即執行,只是第二個參數的傳值方式不一樣。bind返回要執行的函數,需要的時候再執行。(bind後的函數當使用new執行時,綁定無效)
function foo() {
console.log(this.a);
}
var obj = {
a:2
};
var fn = foo.bind( obj );
fn() //2
new fn() //undefined
隱式綁定
當函數存在上下文對象時會影響調用位置
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); //42
箭頭函數
箭頭函數會繼承外層函數調用的 this 綁定