除了之前介紹的call,apply和bind等會對this的指向產生影響,箭頭函數也會產生影響。
箭頭函數作爲bind使用的替代者,不僅僅是讓代碼更簡潔,而且可以改變this的指向,讓失去this的方法重新找回和this的綁定。
廢話不多說,來看個例子
var obj = {
count: 0,
cool: function(){
console.log(this.count)
}
}
var count = 1;
function foo(func){
var count = 2;
console.log(this.count+'balabala') //1balabala
func();
}
obj.cool(); //0
setTimeout(obj.cool,1000); //1
foo(obj.cool); //1
下面來分析一下,第一個調用是obj對象調用的,所以this指向obj,所以結果是obj.count.
第二個調用是setTimeout,這個函數在使用方法的時候會在內部新建一個變量接收第一個方法參數,這個時候調用的本身就是函數的一個引用,這種綁定方式是默認綁定,所以this直接指向的是window對象,所以調用的是window.count.
第三個是在方法內部調用,這個也是傳參數了,也是把原函數的值傳遞過去了,所以也是默認綁定,同上。
現在把方法換成箭頭函數的方法。
var obj = {
count: 0,
cool: ()=>{
console.log(this.count)
}
}
var count = 1;
function foo(func){
var count = 2;
func();
}
obj.cool(); //1
setTimeout(obj.cool,1000); //1
foo(obj.cool); //1
現在就比較一目瞭然了,結果都是1,也就是說函數調用的時候this都是指向的window.這就是箭頭函數的影響,他放棄了普通this綁定的機制,用當前的此法作用域覆蓋了this本來的值。
可以理解爲,他繼承了cool()函數的this綁定(即當前定義位置的上一層)。
爲了驗證這一觀點,下面在運行一組代碼:
var obj = {
count:0,
cool: function coo(){
setTimeout(function(){
this.count++;
console.log(this); setTimeout的參數函數,由於會新定義一個變量並調用函數,所以this指向會斷掉,進而指向window
},1000);
}
}
obj.cool();
這個this打印出來,還是window,就和剛纔說的一樣,默認綁定。
var obj = {
count:0,
cool: function coo(){
setTimeout(()=>{
this.count++;
console.log(this); this繼承了cool的詞法作用域
},1000);
}
}
obj.cool();
這個this,打印出來會出現obj整個對象,也就是指向了cool的詞法作用域。其實就等價於在函數內部加上了self = this.,然後後續的調用都是self去代替this,故會繼承外層函數調用的 this 綁定。
更新分界線---------------------------------------------------------------------------------
如果套用兩層,那他遵循最近的一層。
function foo(){
return (a) => {
//這裏的箭頭函數繼承自foo
console.log(this.a);
}
}
var obj1 = {
a:2
}
var obj2 = {
a:3
}
var bar = foo.call(obj1); //此時相當於在函數內部定義了self = this,而此時的this就是obj1.
bar.call(obj2); //輸出是2,不是3
foo內部創建的箭頭函數會捕獲調用foo時的this,箭頭函數的綁定無法被修改。記住箭頭函數就是根據外層(函數或全局)作用域來決定this的。