一文講透ES6箭頭函數(shù)
這是奶爸碼農(nóng)第70篇原創(chuàng)文章,點擊上方藍字關(guān)注

前言
最近是校招季,有時會問同學(xué)關(guān)于箭頭函數(shù)和普通函數(shù)異同,往往能夠得到一些表面的回答,但不夠全面不夠深入。于是寫一篇來徹底講透箭頭函數(shù)。
箭頭函數(shù)是ES6引入到JavaScript中的,是一種新式的匿名函數(shù)的寫法,類似于其他語言中Lambda函數(shù)。箭頭函數(shù)和傳統(tǒng)函數(shù)有很多的不同,例如作用域、語法寫法等等。
函數(shù)定義
在深入介紹箭頭函數(shù)和傳統(tǒng)函數(shù)異同之前,我們先了解一下傳統(tǒng)函數(shù)的使用,這樣將更好的理解箭頭函數(shù)的異同。
下面是一個sum函數(shù)的定義,可以返回兩個參數(shù)之和。
function sum(a, b) {
return a + b
}
對于傳統(tǒng)函數(shù),你甚至可以在定義之前調(diào)用該函數(shù)
sum(1, 2)
function sum(a, b) {
return a + b
}
你可以通過函數(shù)名,打印出其函數(shù)申明
console.log(sum)
輸出結(jié)果如下:
? sum(a, b) {
return a + b
}
函數(shù)表達式通常可以有個名字,但是也可以是匿名的,意味著函數(shù)是沒有名字的。
下面例子是sum函數(shù)的匿名申明方式:
const sum = function (a, b) {
return a + b
}
這時我們將匿名函數(shù)賦值給了sum變量,如果這時候在定義之前調(diào)用會導(dǎo)致錯誤:
sum(1, 2)
const sum = function (a, b) {
return a + b
}
錯誤返回:Uncaught ReferenceError: Cannot access 'sum' before initialization
我們也可以把sum打印出來:
const sum = function (a, b) {
return a + b
}
console.log(sum)
打印出來的結(jié)果如下:
? (a, b) {
return a + b
}
sum是一個匿名函數(shù),而不是一個有名字的函數(shù)。
箭頭函數(shù)
箭頭函數(shù)和普通函數(shù)有非常多的不同,其中最大的不同是箭頭函數(shù)沒有沒有自己的this綁定,沒有prototype,同時也不能被用做構(gòu)造函數(shù)。同時,箭頭函數(shù)可以作為普通函數(shù)提供更為簡潔的寫法。
this綁定
在JavaScript中,this往往是一個比較復(fù)雜詭異的事情。在JavaScript中有bind、apply、call等方法會影響this所指定的對象。
箭頭函數(shù)的this是語義層面的,因此,箭頭函數(shù)中的this是由上下文作用域決定的。下面的例子會解釋this在普通函數(shù)和箭頭函數(shù)的區(qū)別:
const printNumbers = {
phrase: 'The current value is:',
numbers: [1, 2, 3, 4],
loop() {
this.numbers.forEach(function (number) {
console.log(this.phrase, number)
})
},
}
你也許會期望loop函數(shù)會打印出文本和對應(yīng)的數(shù)字,然后真正返回的內(nèi)容其實是undefined
printNumbers.loop()
輸出:
undefined 1
undefined 2
undefined 3
undefined 4
在上面的例子中,this.phrase代表了undefined,說明在forEach方法中的匿名函數(shù)中的this并不會指向printNumber對象。這是因為普通函數(shù)并不是通過上下文作用域來決定this的值,而是通過實際調(diào)用函數(shù)的對象來決定的。
在老版本的JavaScript,你可以通過bind方法來顯示的綁定this。使用bind的方式如下:
const printNumbers = {
phrase: 'The current value is:',
numbers: [1, 2, 3, 4],
loop() {
// 將外部的printNumber對象綁定到內(nèi)部forEach函數(shù)中的'this'
this.numbers.forEach(
function (number) {
console.log(this.phrase, number)
}.bind(this),
)
},
}
printNumbers.loop()
這將輸出正確的結(jié)果:
The current value is: 1
The current value is: 2
The current value is: 3
The current value is: 4
箭頭函數(shù)提供了一個更為優(yōu)雅的解決方案,由于其this的指向是由上下文作用域來決定的,因此它會指向printNumbers對象:
const printNumbers = {
phrase: 'The current value is:',
numbers: [1, 2, 3, 4],
loop() {
this.numbers.forEach((number) => {
console.log(this.phrase, number)
})
},
}
printNumbers.loop()
箭頭函數(shù)作為對象方法
箭頭函數(shù)在循環(huán)中可以很好的使用,但是作為對象方法卻會造成問題。
const printNumbers = {
phrase: 'The current value is:',
numbers: [1, 2, 3, 4],
loop: () => {
this.numbers.forEach((number) => {
console.log(this.phrase, number)
})
},
}
調(diào)用loop方法
printNumbers.loop()
結(jié)果會出現(xiàn)如下錯誤:
Uncaught TypeError: Cannot read property 'forEach' of undefined
這是因為在loop箭頭函數(shù)申明的時候,this指向并不會是printNumbers對象,而是外部的Window。而Window上面并沒有numbers字段,從而導(dǎo)致錯誤。因此,對象方法一般使用傳統(tǒng)方法。
箭頭函數(shù)沒有Prototype和構(gòu)造函數(shù)
在JavaScript中的Function或者Class中都會有一個Prototype屬性,這個可以用于對象拷貝或者繼承。
function myFunction() {
this.value = 5
}
// Log the prototype property of myFunction
console.log(myFunction.prototype)
輸出:
{constructor: ?}
但是,箭頭函數(shù)是不存在Prototype屬性,我們可以嘗試打印出箭頭函數(shù)的Prototype。
const myArrowFunction = () => {}
// Attempt to log the prototype property of myArrowFunction
console.log(myArrowFunction.prototype)
輸出:
undefined
同時,由于沒有Prototype屬性,因此也沒法通過new進行實例化。
const arrowInstance = new myArrowFunction()
console.log(arrowInstance)
輸出錯誤:
Uncaught TypeError: myArrowFunction is not a constructor
箭頭函數(shù)除了這些變化之外,還有些語法上的不同,可以讓寫法變得更簡潔。
隱含返回
傳統(tǒng)的方法都是需要大括號{},并且通過return語句返回值。
const sum = (a, b) => {
return a + b
}
箭頭函數(shù)可以簡化函數(shù)聲明,并且提供隱含返回值。
const sum = (a, b) => a + b
單個參數(shù)省略括號
例如:
const square = (x) => x * x
當(dāng)只有一個參數(shù)的時候,可以省略(),寫成如下形式:
const square = x => x * x
square(10)
輸出:100
有些代碼庫總是嘗試忽略(),而有的代碼庫總是保留,尤其是采用TypeScript的代碼庫,需要聲明每個參數(shù)的類型。因此,你需要首先規(guī)定好代碼庫的風(fēng)格,并且始終保持。
寫在最后
在這篇文章中,你了解了箭頭函數(shù)和傳統(tǒng)函數(shù)的區(qū)別。箭頭函數(shù)始終是匿名的,沒有Prototype或者構(gòu)造函數(shù),無法用new進行實例化,并且是通過語義上下文來決定this指向。然后,你又了解了關(guān)于箭頭函數(shù)的語法優(yōu)化,例如隱含返回、單個參數(shù)省略括號等。
- End -
『奶爸碼農(nóng)』從事互聯(lián)網(wǎng)研發(fā)工作10+年,經(jīng)歷IBM、SAP、陸金所、攜程等國內(nèi)外IT公司,目前在美團負(fù)責(zé)餐飲相關(guān)大前端技術(shù)團隊,定期分享關(guān)于大前端技術(shù)、投資理財、個人成長的思考與總結(jié)。
