箭頭函數(shù)與普通函數(shù)的區(qū)別
作為ES6中新加入的箭頭函數(shù)語法,深受廣大開發(fā)人員的喜愛衫哥,也是平時(shí)前端面試過程中經(jīng)常會(huì)被提及問道的典型題目。它不僅簡化了我們的代碼,而且也讓開發(fā)人員擺脫了“飄忽不定”的this指向怜校,本文就箭頭函數(shù)與普通函數(shù)的區(qū)別進(jìn)行一些分析。
在我看來注竿,面試官最關(guān)注的也是兩者最關(guān)鍵的區(qū)別就是this指向的區(qū)別茄茁,普通函數(shù)中的this指向函數(shù)被調(diào)用的對象,因此對于不同的調(diào)用者巩割,this的值是不同的裙顽。而箭頭函數(shù)中并沒有自己的this(同時(shí),箭頭函數(shù)中也沒有其他的局部變量宣谈,如this愈犹,argument,super等)闻丑,所以箭頭函數(shù)中的this是固定的漩怎,它指向定義該函數(shù)時(shí)所在的對象。
普通函數(shù)
相信大家對普通函數(shù)的用法已經(jīng)非常熟悉了嗦嗡,下面我們舉一個(gè)簡單的例子勋锤。
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
上述代碼中,出現(xiàn)了三種情況:
- 直接通過obj調(diào)用其中的方法foo侥祭,此時(shí)怪得,this就會(huì)指向調(diào)用foo函數(shù)的對象,也就是obj;
- 將obj對象賦給一個(gè)新的對象bar卑硫,此時(shí)通過bar調(diào)用foo函數(shù)徒恋,this的值就會(huì)指向調(diào)用者bar;
- 將obj.foo賦給一個(gè)新對象baz欢伏,通過baz()調(diào)用foo函數(shù)入挣,此時(shí)的this指向window;
由此我們可以得出結(jié)論:
- 普通函數(shù)的this總是指向它的直接調(diào)用者硝拧。
- 在嚴(yán)格模式下径筏,沒找到直接調(diào)用者,則函數(shù)中的this是undefined障陶。
- 在默認(rèn)模式下(非嚴(yán)格模式)滋恬,沒找到直接調(diào)用者,則函數(shù)中的this指向window抱究。
再考慮一下下面的情況:
var obj = {
a : 1,
foo : function(){
setTimeout(
function(){console.log(this.a),3000})
}
}
obj.foo(); //undefined
你可能會(huì)認(rèn)為此時(shí)的輸出應(yīng)該為1恢氯,但是結(jié)果卻是undefined。因?yàn)榇藭r(shí)this的指向是全局的window對象。
通過以上例子勋拟,可以得出以下總結(jié):
- 對于方法(即通過對象調(diào)用了該函數(shù))勋磕,普通函數(shù)中的this總是指向它的調(diào)用者。
- 對于一般函數(shù)敢靡,this指向全局變量(非嚴(yán)格模式下)或者undefined(嚴(yán)格模式下)挂滓。在上例中setTimeout中的function未被任何對象調(diào)用,因此它的this指向還是window對象啸胧。因此赶站,這也可以總結(jié)成:javascript 的this 可以簡單的認(rèn)為是后期綁定,沒有地方綁定的時(shí)候纺念,默認(rèn)綁定window或undefined亲怠。
如果我們希望可以在上例的setTimeout函數(shù)中使用this要怎么做呢?在箭頭函數(shù)出現(xiàn)之前柠辞,我們往往會(huì)使用以下兩種方法:
- 在setTimeout函數(shù)的外部,也就是上層函數(shù)foo內(nèi)部通過將this值賦給一個(gè)臨時(shí)變量來實(shí)現(xiàn)主胧。
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
這種現(xiàn)象在ES6引入箭頭函數(shù)后得到了改善。
箭頭函數(shù)
箭頭函數(shù)是ES6中引入的新特性踪栋,使用方法為:
()=>{console.log(this)}
其中()內(nèi)是要帶入的參數(shù)焙格,{}內(nèi)是要執(zhí)行的語句。箭頭函數(shù)是函數(shù)式編程的一種體現(xiàn)夷都,函數(shù)式編程將更多的關(guān)注點(diǎn)放在輸入和輸出的關(guān)系眷唉,省去了過程的一些因素,因此箭頭函數(shù)中沒有自己的this囤官,arguments冬阳,new target(ES6)和 super(ES6)。箭頭函數(shù)相當(dāng)于匿名函數(shù)党饮,因此不能使用new來作為構(gòu)造函數(shù)使用肝陪。
箭頭函數(shù)中的this始終指向其父級作用域中的this。換句話說刑顺,箭頭函數(shù)會(huì)捕獲其所在的上下文的this值氯窍,作為自己的this值。任何方法都改變不了其指向蹲堂,如call(), bind(), apply()狼讨。在箭頭函數(shù)中調(diào)用 this 時(shí),僅僅是簡單的沿著作用域鏈向上尋找政供,找到最近的一個(gè) this 拿來使用,它與調(diào)用時(shí)的上下文無關(guān)犬耻。我們用代碼來解釋一下。
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: ?, e: ?
},
d:function(){
return ()=>{
console.log(this.a); // 10
}
},
e:function(){
setTime
}
}
obj.b();
obj.c();
obj.d()();
簡單分析一下代碼执泰,obj.b()中的this會(huì)繼承父級上下文中的this值,也就是與obj有相同的this指向计济,為全局變量window。obj.c()的this指向即為調(diào)用者obj排苍,obj.d().()中的this也繼承自父級上下文中的this沦寂,即d的this指向传藏,也就是obj彤守。
通過這個(gè)例子具垫,也就可以大概的讓我們理解普通函數(shù)中的this和匿名函數(shù)中的this指向差別,從而更好的在工作中根據(jù)我們的需求正確合理地使用這兩種函數(shù)卦碾。