一文講透ES6箭頭函數

前言

最近是校招季,有時會問同窗關於箭頭函數和普通函數異同,每每可以獲得一些表面的回答,但不夠全面不夠深刻。因而寫一篇來完全講透箭頭函數。前端

箭頭函數是ES6引入到JavaScript中的,是一種新式的匿名函數的寫法,相似於其餘語言中Lambda函數。箭頭函數和傳統函數有不少的不一樣,例如做用域、語法寫法等等。markdown

函數定義

在深刻介紹箭頭函數和傳統函數異同以前,咱們先了解一下傳統函數的使用,這樣將更好的理解箭頭函數的異同。app

下面是一個sum函數的定義,能夠返回兩個參數之和。函數

function sum(a, b) {
  return a + b
}
複製代碼

對於傳統函數,你甚至能夠在定義以前調用該函數oop

sum(1, 2)

function sum(a, b) {
  return a + b
}
複製代碼

你能夠經過函數名,打印出其函數申明優化

console.log(sum)
複製代碼

輸出結果以下:this

ƒ sum(a, b) {
  return a + b
}
複製代碼

函數表達式一般能夠有個名字,可是也能夠是匿名的,意味着函數是沒有名字的。spa

下面例子是sum函數的匿名申明方式:prototype

const sum = function (a, b) {
  return a + b
}
複製代碼

這時咱們將匿名函數賦值給了sum變量,若是這時候在定義以前調用會致使錯誤:code

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)
複製代碼

打印出來的結果以下:

ƒ (a, b) {
  return a + b
}
複製代碼

sum是一個匿名函數,而不是一個有名字的函數。

箭頭函數

箭頭函數和普通函數有很是多的不一樣,其中最大的不一樣是箭頭函數沒有沒有本身的this綁定,沒有prototype,同時也不能被用作構造函數。同時,箭頭函數能夠做爲普通函數提供更爲簡潔的寫法。

this綁定

在JavaScript中,this每每是一個比較複雜詭異的事情。在JavaScript中有bind、apply、call等方法會影響this所指定的對象。

箭頭函數的this是語義層面的,所以,箭頭函數中的this是由上下文做用域決定的。下面的例子會解釋this在普通函數和箭頭函數的區別:

const printNumbers = {
  phrase: 'The current value is:',
  numbers: [1, 2, 3, 4],

  loop() {
    this.numbers.forEach(function (number) {
      console.log(this.phrase, number)
    })
  },
}
複製代碼

你也許會指望loop函數會打印出文本和對應的數字,而後真正返回的內容實際上是undefined:

printNumbers.loop()
複製代碼

輸出:

undefined 1
undefined 2
undefined 3
undefined 4
複製代碼

在上面的例子中,this.phrase表明了undefined,說明在forEach方法中的匿名函數中的this並不會指向printNumber對象。這是由於普通函數並非經過上下文做用域來決定this的值,而是經過實際調用函數的對象來決定的。

在老版本的JavaScript,你能夠經過bind方法來顯示的綁定this。使用bind的方式以下:

const printNumbers = {
  phrase: 'The current value is:',
  numbers: [1, 2, 3, 4],

  loop() {
    // 將外部的printNumber對象綁定到內部forEach函數中的'this'
    this.numbers.forEach(
      function (number) {
        console.log(this.phrase, number)
      }.bind(this),
    )
  },
}

printNumbers.loop()
複製代碼

這將輸出正確的結果:

The current value is: 1
The current value is: 2
The current value is: 3
The current value is: 4
複製代碼

箭頭函數提供了一個更爲優雅的解決方案,因爲其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()
複製代碼

箭頭函數做爲對象方法

箭頭函數在循環中能夠很好的使用,可是做爲對象方法卻會形成問題。

const printNumbers = {
  phrase: 'The current value is:',
  numbers: [1, 2, 3, 4],

  loop: () => {
    this.numbers.forEach((number) => {
      console.log(this.phrase, number)
    })
  },
}
複製代碼

調用loop方法

printNumbers.loop()
複製代碼

結果會出現以下錯誤:

Uncaught TypeError: Cannot read property 'forEach' of undefined
複製代碼

這是由於在loop箭頭函數申明的時候,this指向並不會是printNumbers對象,而是外部的Window。而Window上面並無numbers字段,從而致使錯誤。所以,對象方法通常使用傳統方法。

箭頭函數沒有Prototype和構造函數

在JavaScript中的Function或者Class中都會有一個Prototype屬性,這個能夠用於對象拷貝或者繼承。

function myFunction() {
  this.value = 5
}

// Log the prototype property of myFunction
console.log(myFunction.prototype)
複製代碼

輸出:

{constructor: ƒ}
複製代碼

可是,箭頭函數是不存在Prototype屬性,咱們能夠嘗試打印出箭頭函數的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
複製代碼

箭頭函數除了這些變化以外,還有些語法上的不一樣,可讓寫法變得更簡潔。

隱含返回

傳統的方法都是須要大括號{},而且經過return語句返回值。

const sum = (a, b) => {
  return a + b
}
複製代碼

箭頭函數能夠簡化函數聲明,而且提供隱含返回值。

const sum = (a, b) => a + b
複製代碼

單個參數省略括號

例如:

const square = (x) => x * x
複製代碼

當只有一個參數的時候,能夠省略(),寫成以下形式:

const square = x => x * x
square(10)
複製代碼

輸出:100

有些代碼庫老是嘗試忽略(),而有的代碼庫老是保留,尤爲是採用TypeScript的代碼庫,須要聲明每一個參數的類型。所以,你須要首先規定好代碼庫的風格,而且始終保持。

寫在最後

在這篇文章中,你瞭解了箭頭函數和傳統函數的區別。箭頭函數始終是匿名的,沒有Prototype或者構造函數,沒法用new進行實例化,而且是經過語義上下文來決定this指向。而後,你又瞭解了關於箭頭函數的語法優化,例如隱含返回、單個參數省略括號等。

『奶爸碼農』從事互聯網研發工做10+年,經歷IBM、SAP、陸金所、攜程等國內外IT公司,目前在美團負責餐飲相關大前端技術團隊,按期分享關於大前端技術、投資理財、我的成長的思考與總結。

相關文章
相關標籤/搜索