JS之箭頭函數


箭頭函數是ES6引入到JavaScript中的,是一種新式的匿名函數的寫法,類似於其他語言中Lambda函數。箭頭函數和傳統函數有很多的不同,例如作用域、語法寫法等等。

一、傳統函數的定義

1、普通函數定義

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

function sum(a, b) {
  return a + b
}

對於傳統函數,你甚至可以在定義之前調用該函數

sum(1, 2)

function sum(a, b) {
  return a + b
}

你可以通過函數名,打印出其函數申明

console.log(sum)

輸出結果如下:

ƒ sum(a, b) {
  return a + b
}

函數表達式通常可以有個名字,但是也可以是匿名的,意味着函數是沒有名字的。

2、匿名函數

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

const sum = function (a, b) {
  return a + b
}

這時我們將匿名函數賦值給了sum變量,如果這時候在定義之前調用會導致錯誤:

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,不能被用做構造函數。同時,箭頭函數可以作為普通函數提供更為簡潔的寫法。

1、箭頭函數定義

寫法非常簡潔:

const sum = (a, b) => { return a + b }

可以簡化函數聲明,並且提供隱含返回值:

const sum = (a, b) => a + b

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

const square = x => x * x

2、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字段,從而導致錯誤。因此,對象方法一般使用傳統方法。

3、箭頭函數沒有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

 

總結:

箭頭函數始終是匿名的,沒有Prototype或者構造函數,無法用new進行實例化,並且是通過語義上下文來決定this指向。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM