箭頭函數與普通函數的差別
作為ES6中新加入的箭頭函數文法,深受廣大開發人員的喜愛,也是平時前端面試過程中經常會被提及問道的典型題目。它不僅簡化了我們的代碼,而且也讓開發人員擺脫了“飄忽不定”的this指向,本文就箭頭函數與普通函數的差別進行一些分析。
在我看來,面試官最關注的也是兩者最關鍵的差別就是this指向的差別,普通函數中的this指向函數被調用的對象,是以對于不同的調用者,this的值是不同的。而箭頭函數中并沒有自己的this(同時,箭頭函數中也沒有其他的局部變量,如this,argument,super等),是以箭頭函數中的this是固定的,它指向定義該函數時所在的對象。
普通函數
相信大家對普通函數的用法已經非常熟悉了,下面我們舉一個簡單的例子。
var a = 3;
var obj = {
a : 1,
foo : function(){
console.log(this.a);
}
}
obj.foo(); //1
var bar = obj;
bar.a = 2;
bar.foo(); //2
var baz = obj.foo;
baz(); //3
上述代碼中,出現了三種情況:
- 直接通過obj調用其中的方法foo,此時,this就會指向調用foo函數的對象,也就是obj;
- 将obj對象賦給一個新的對象bar,此時通過bar調用foo函數,this的值就會指向調用者bar;
- 将obj.foo賦給一個新對象baz,通過baz()調用foo函數,此時的this指向window;
由此我們可以得出結論:
- 普通函數的this總是指向它的直接調用者。
- 在嚴格模式下,沒找到直接調用者,則函數中的this是undefined。
- 在預設模式下(非嚴格模式),沒找到直接調用者,則函數中的this指向window。
再考慮一下下面的情況:
var obj = {
a : 1,
foo : function(){
setTimeout(
function(){console.log(this.a),3000})
}
}
obj.foo(); //undefined
你可能會認為此時的輸出應該為1,但是結果卻是undefined。因為此時this的指向是全局的window對象。
通過以上例子,可以得出以下總結:
- 對于方法(即通過對象調用了該函數),普通函數中的this總是指向它的調用者。
- 對于一般函數,this指向全局變量(非嚴格模式下)或者undefined(嚴格模式下)。在上例中setTimeout中的function未被任何對象調用,是以它的this指向還是window對象。是以,這也可以總結成:javascript 的this 可以簡單的認為是後期綁定,沒有地方綁定的時候,預設綁定window或undefined。
如果我們希望可以在上例的setTimeout函數中使用this要怎麼做呢?在箭頭函數出現之前,我們往往會使用以下兩種方法:
- 在setTimeout函數的外部,也就是上層函數foo内部通過将this值賦給一個臨時變量來實作。
var obj = {
a : 1,
foo : function(){
var that = this;
setTimeout(
function(){console.log(that.a),3000})
}
}
obj.foo(); //1
- 通過bind()來綁定this。
var obj = {
a : 1,
foo : function(){
setTimeout(
function(){console.log(this.a),3000}.bind(this))
}
}
obj.foo(); //1
這種現象在ES6引入箭頭函數後得到了改善。
箭頭函數
箭頭函數是ES6中引入的新特性,使用方法為:
()=>{console.log(this)}
其中()内是要帶入的參數,{}内是要執行的語句。箭頭函數是函數式程式設計的一種展現,函數式程式設計将更多的關注點放在輸入和輸出的關系,省去了過程的一些因素,是以箭頭函數中沒有自己的this,arguments,new target(ES6)和 super(ES6)。箭頭函數相當于匿名函數,是以不能使用new來作為構造函數使用。
箭頭函數中的this始終指向其父級作用域中的this。換句話說,箭頭函數會捕獲其所在的上下文的this值,作為自己的this值。任何方法都改變不了其指向,如call(), bind(), apply()。在箭頭函數中調用 this 時,僅僅是簡單的沿着作用域鍊向上尋找,找到最近的一個 this 拿來使用,它與調用時的上下文無關。我們用代碼來解釋一下。
var obj = {
a: 10,
b: () => {
console.log(this.a); // undefined
console.log(this); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
},
c: function() {
console.log(this.a); // 10
console.log(this); // {a: 10, b: ƒ, c: ƒ}
},
d:function(){
return ()=>{
console.log(this.a); // 10
}
},
e:function(){
setTime
}
}
obj.b();
obj.c();
obj.d()();
簡單分析一下代碼,obj.b()中的this會繼承父級上下文中的this值,也就是與obj有相同的this指向,為全局變量window。obj.c()的this指向即為調用者obj,obj.d().()中的this也繼承自父級上下文中的this,即d的this指向,也就是obj。
通過這個例子,也就可以大概的讓我們了解普通函數中的this和匿名函數中的this指向差别,進而更好的在工作中根據我們的需求正确合理地使用這兩種函數。
連結:https://www.jianshu.com/p/e5fe25edd78a