搜尋
首頁web前端js教程一文帶你了解JS箭頭函數

一文帶你了解JS箭頭函數

Nov 10, 2022 pm 03:58 PM
javascript箭頭函數

一文帶你了解JS箭頭函數

本文可以讓你了解所有關於JavaScript箭頭函數的資訊。我們將告訴你如何使用ES6的箭頭語法,以及在程式碼中使用箭頭函數時需要注意的一些常見錯誤。你會看到很多例子來說明它們是如何運作的。

JavaScript的箭頭函數隨著ECMAScript 2015的發布而到來,也稱為ES6。由於其簡潔的語法和對this關鍵字的處理,箭頭函數迅速成為開發者最喜歡的功能。

箭頭函數語法

函數就像食譜一樣,你在其中儲存有用的指令,以完成你需要在程式中發生的事情,例如執行一個動作或傳回一個值。透過呼叫函數,來執行食譜中包含的步驟。你可以在每次呼叫函數時都這樣做,而不需要一次又一次地重寫食譜。

下面是在JavaScript中宣告函數並呼叫它的標準方法:

// function declaration
function sayHiStranger() {
  return 'Hi, stranger!'
}

// call the function
sayHiStranger()

你也可以寫同樣的函數作為函數表達式,就行這樣:

const sayHiStranger = function () {
  return 'Hi, stranger!'
}

JavaScript箭頭函數總是表達式。以下是如何使用箭頭符號重寫上面的函數:

const sayHiStranger = () => 'Hi, stranger'

這樣做的好處包括:

  • #程式碼只有一行
  • 沒有function關鍵字
  • 沒有return關鍵字
  • 沒有大括號{}

在JavaScript中,函數是一等公民。你可以把函數儲存在變數中,把它們當作參數傳遞給其他函數,並從其他函數中把它們當作值傳回。你可以使用JavaScript箭頭函數來做所有這些事情。

無圓括號語法

在上述範例中,函數是沒有參數的。在本例中,你必須在胖箭頭符號(=>)之前加上一對空的圓括號()。當有多個參數時同理:

const getNetflixSeries = (seriesName, releaseDate) => `The ${seriesName} series was released in ${releaseDate}`
// call the function
console.log(getNetflixSeries('Bridgerton', '2020') )
// output: The Bridgerton series was released in 2020

如果只有一個參數,你可以省略圓括號(你不必如此,但你可以這麼做):

const favoriteSeries = seriesName => seriesName === "Bridgerton" ? "Let's watch it" : "Let's go out"
// call the function
console.log(favoriteSeries("Bridgerton"))
// output: "Let's watch it"

當你這麼做的時候要小心一點。比方說,你決定使用預設參數,你必須將其包裹在圓括號中:

// with parentheses: correct
const bestNetflixSeries = (seriesName = "Bridgerton") => `${seriesName} is the best`
// outputs: "Bridgerton is the best"
console.log(bestNetflixSeries())

// no parentheses: error
const bestNetflixSeries = seriesName = "Bridgerton" => `${seriesName} is the best`
// Uncaught SyntaxError: invalid arrow-function arguments (parentheses around the arrow-function may help)

#隱含回傳

當函數體內只有一個表達式時,你可以讓ES6的箭頭語法更簡潔。你可以把所有內容放在一行,去掉大括號,並移除return關鍵字。

你已經在上面的範例中看到了這些漂亮的一行程式碼是如何運作的。下面的orderByLikes()函數傳回奈飛劇集物件的數組,依照最高按讚數排序:

// using the JS sort() function to sort the titles in descending order 
// according to the number of likes (more likes at the top, fewer at the bottom
const orderByLikes = netflixSeries.sort((a, b) => b.likes - a.likes)

// call the function 
// output:the titles and the n. of likes in descending order
console.log(orderByLikes)

這種寫法很酷,但是要注意程式碼的可讀性。特別是在使用單行和無括號的ES6箭頭語法對一堆箭頭函數進行排序時。就像這個例子:

const greeter = greeting => name => `${greeting}, ${name}!`

那裡發生了什麼事?嘗試使用常規的函數語法:

function greeter(greeting) {
  return function(name) {
    return `${greeting}, ${name}!` 
  }
}

現在,你可以快速看到外部函數greeter如何具有參數greeting,並傳回一個匿名函數。這個內部函數又有一個叫做name的參數,並且使用greetingname的值回傳一個字串。以下是呼叫函數的方式:

const myGreet = greeter('Good morning')
console.log( myGreet('Mary') )   

// output: 
"Good morning, Mary!"

注意隱含回傳錯誤

#當你的JavaScript箭頭函數包含不只一個語句,你需要在大括號內包裹所有語句,並使用return關鍵字。

在下面的程式碼中,該函數建立了一個包含幾個Netflix劇集的標題和摘要的物件:

const seriesList = netflixSeries.map( series => {
  const container = {}
  container.title = series.name 
  container.summary = series.summary

  // explicit return
  return container
} )

.map()函數中的箭頭函數在一系列的語句中展開,在語句的最後回傳一個物件。這使得在函數主體周圍使用大括號是不可避免的。

另外,由於正在使用花括號,隱式回傳便不是選項。你必須明確地使用return關鍵字。

如果你的函數使用隱式回傳來傳回一個物件字面量,你需要使用圓括號來包覆該物件字面量。不這樣做將導致錯誤,因為JavaScript引擎將物件字面量的大括號錯誤地解析為函數的大括號。正如你剛才注意到的,當你在一個箭頭函數中使用大括號時,你不能省略return關鍵字。

前面程式碼的較短版本示範了這種語法:

// Uncaught SyntaxError: unexpected token: ':'
const seriesList = netflixSeries.map(series => { title: series.name });

// Works fine
const seriesList = netflixSeries.map(series => ({ title: series.name }));

無法命名箭頭函數

function關鍵字和參數列表之間沒有名稱標識的函數稱為匿名函數。下面是常規匿名函數表達式的樣子:

const anonymous = function() {
  return 'You can\'t identify me!' 
}

箭頭函數都是匿名函數:

const anonymousArrowFunc = () => 'You can\'t identify me!'

從ES6開始,變數和方法可以透過匿名函數的語法位置,使用 name屬性來推斷其名稱。這使得在檢查函數值或報告錯誤時有可能識別該函數。

使用anonymousArrowFunc檢查一下:

console.log(anonymousArrowFunc.name)
// output: "anonymousArrowFunc"

需要注意的是,只有当匿名函数被分配给一个变量时,这个可以推断的name属性才会存在,正如上面的例子。如果你使用匿名函数作为回调函数,你就会失去这个有用的功能。在下面的演示中,.setInterval()方法中的匿名函数无法利用name属性:

let counter = 5
let countDown = setInterval(() => {
  console.log(counter)
  counter--
  if (counter === 0) {
    console.log("I have no name!!")
    clearInterval(countDown)
  }
}, 1000)

这还不是全部。这个推断的name属性仍然不能作为一个适当的标识符,你可以用它来指代函数本身--比如递归、解除绑定事件等。

如何处理this关键字

关于箭头函数,最重要的一点是它们处理this关键字的方式。特别是,箭头函数内的this关键字不会重新绑定。

为了说明这意味着什么,请查看下面的演示。

这里有一个按钮。点击按钮会触发一个从5到1的反向计数器,它显示在按钮本身。

<button class="start-btn">Start Counter</button>

...

const startBtn = document.querySelector(".start-btn");

startBtn.addEventListener(&#39;click&#39;, function() {
  this.classList.add(&#39;counting&#39;)
  let counter = 5;
  const timer = setInterval(() => {
    this.textContent = counter 
    counter -- 
    if(counter < 0) {
      this.textContent = &#39;THE END!&#39;
      this.classList.remove(&#39;counting&#39;)
      clearInterval(timer)
    }
  }, 1000) 
})

注意到.addEventListener()方法里面的事件处理器是一个常规的匿名函数表达式,而不是一个箭头函数。为什么呢?如果在函数内部打印this的值,你会看到它引用了监听器所连接的按钮元素,这正是我们所期望的,也是程序按计划工作所需要的:

startBtn.addEventListener(&#39;click&#39;, function() {
  console.log(this)
  ...
})

下面是它在Firefox开发人员工具控制台中的样子:

一文帶你了解JS箭頭函數

然后,尝试使用箭头函数来替代常规函数,就像这样:

startBtn.addEventListener(&#39;click&#39;, () => {
  console.log(this)
  ...
})

现在,this不再引用按钮元素。相反,它引用Window对象:

一文帶你了解JS箭頭函數

这意味着,如果你想要在按钮被点击之后,使用this来为按钮添加class,你的代码就无法正常工作:

// change button&#39;s border&#39;s appearance
this.classList.add(&#39;counting&#39;)

下面是控制台中的错误信息:

一文帶你了解JS箭頭函數

当你在JavaScript中使用箭头函数,this关键字的值不会被重新绑定。它继承自父作用域(也称为词法作用域)。在这种特殊情况下,箭头函数被作为参数传递给startBtn.addEventListener()方法,该方法位于全局作用域中。因此,函数处理器中的this也被绑定到全局作用域中--也就是Window对象。

因此,如果你想让this引用程序中的开始按钮,正确的做法是使用一个常规函数,而不是一个箭头函数。

匿名箭头函数

在上面的演示中,接下来要注意的是.setInterval()方法中的代码。在这里,你也会发现一个匿名函数,但这次是一个箭头函数。为什么?

请注意,如果你使用常规函数,this值会是多少:

const timer = setInterval(function() {
  console.log(this)
  ...
}, 1000)

button元素吗?并不是。这个值将会是Window对象!

事实上,上下文已经发生了变化,因为现在this在一个非绑定的或全局的函数中,它被作为参数传递给.setInterval() 。因此,this关键字的值也发生了变化,因为它现在被绑定到全局作用域。

在这种情况下,一个常见的hack手段是包括另一个变量来存储this关键字的值,这样它就会一直指向预期的元素--在这种情况下,就是button元素:

const that = this
const timer = setInterval(function() {
  console.log(that)
  ...
}, 1000)

你也可以使用.bind()来解决这个问题:

const timer = setInterval(function() {
  console.log(this)
  ...
}.bind(this), 1000)

有了箭头函数,问题就彻底消失了。下面是使用箭头函数时this的值:

const timer = setInterval( () => { 
  console.log(this)
  ...
}, 1000)

一文帶你了解JS箭頭函數

这次,控制台打印了button,这就是我们想要的。事实上,程序要改变按钮的文本,所以它需要this来指代button元素:

const timer = setInterval( () => { 
  console.log(this)
 // the button&#39;s text displays the timer value
  this.textContent = counter
}, 1000)

箭头函数没有自己的this上下文。它们从父级继承this的值,正是因为这个特点,在上面这种情况下就是很好的选择。

不正常工作的情况

箭头函数并不只是在JavaScript中编写函数的一种花里胡哨的新方法。它们有自己的局限性,这意味着在有些情况下你不想使用箭头函数。让我们看看更多的例子。

箭头函数作为对象方法

箭头函数作为对象上的方法不能很好地工作。

考虑这个netflixSeries对象,上面有一些属性和一系列方法。调用console.log(netflixSeries.getLikes()) 应该会打印一条信息,说明当前喜欢的人数。console.log(netflixSeries.addLike())应该会增加一个喜欢的人数,然后在控制台上打印新值:

const netflixSeries = {
  title: &#39;After Life&#39;, 
  firstRealease: 2019,
  likes: 5,
  getLikes: () => `${this.title} has ${this.likes} likes`,
  addLike: () => {  
    this.likes++
    return `Thank you for liking ${this.title}, which now has ${this.likes} likes`
  } 
}

相反,调用.getLikes()方法返回'undefined has NaN likes',调用.addLike()方法返回'Thank you for liking undefined, which now has NaN likes'。因此,this.titlethis.likes未能分别引用对象的属性titlelikes

这次,问题出在箭头函数的词法作用域上。对象方法中的this引用的是父对象的范围,在本例中是Window对象,而不是父对象本身--也就是说,不是netflixSeries对象。

当然,解决办法是使用常规函数:

const netflixSeries = {
  title: &#39;After Life&#39;, 
  firstRealease: 2019,
  likes: 5,
  getLikes() {
    return `${this.title} has ${this.likes} likes`
  },
  addLike() { 
    this.likes++
    return `Thank you for liking ${this.title}, which now has ${this.likes} likes`
  } 
}

// call the methods 
console.log(netflixSeries.getLikes())
console.log(netflixSeries.addLike())

// output: 
After Life has 5 likes
Thank you for liking After Life, which now has 6 likes

箭头函数与第三方库

另一个需要注意的问题是,第三方库通常会绑定方法调用,因此this值会指向一些有用的东西。

比如说,在Jquery事件处理器内部,this将使你能够访问处理器所绑定的DOM元素:

$(&#39;body&#39;).on(&#39;click&#39;, function() {
  console.log(this)
})
// <body>

但是如果我们使用箭头函数,正如我们所看到的,它没有自己的this上下文,我们会得到意想不到的结果:

$(&#39;body&#39;).on(&#39;click&#39;, () =>{
  console.log(this)
})
// Window

下面是使用Vue的其他例子:

new Vue({
  el: app,
  data: {
    message: &#39;Hello, World!&#39;
  },
  created: function() {
    console.log(this.message);
  }
})
// Hello, World!

created钩子内部,this被绑定到Vue实例上,因此会显示'Hello, World!'信息。

然而如果我们使用箭头函数,this将会指向父作用域,上面没有message属性:

new Vue({
  el: app,
  data: {
    message: &#39;Hello, World!&#39;
  },
  created: () => {
    console.log(this.message);
  }
})
// undefined

箭头函数没有arguments对象

有时,你可能需要创建一个具有无限参数个数的函数。比如,假设你想创建一个函数,列出你最喜欢的奈飞剧集,并按照偏好排序。然而,你还不知道你要包括多少个剧集。JavaScript提供了arguments对象。这是一个类数组对象(不是完整的数组),在调用时存储传递给函数的值。

尝试使用箭头函数实现此功能:

const listYourFavNetflixSeries = () => {
  // we need to turn the arguments into a real array 
  // so we can use .map()
  const favSeries = Array.from(arguments) 
  return favSeries.map( (series, i) => {
    return `${series} is my #${i +1} favorite Netflix series`  
  } )
  console.log(arguments)
}

console.log(listYourFavNetflixSeries(&#39;Bridgerton&#39;, &#39;Ozark&#39;, &#39;After Life&#39;))

当你调用该函数时,你会得到以下错误:Uncaught ReferenceError: arguments is not defined。这意味着arguments对象在箭头函数中是不可用的。事实上,将箭头函数替换成常规函数就可以了:

const listYourFavNetflixSeries = function() {
   const favSeries = Array.from(arguments) 
   return favSeries.map( (series, i) => {
     return `${series} is my #${i +1} favorite Netflix series`  
   } )
   console.log(arguments)
 }
console.log(listYourFavNetflixSeries(&#39;Bridgerton&#39;, &#39;Ozark&#39;, &#39;After Life&#39;))

// output: 
["Bridgerton is my #1 favorite Netflix series",  "Ozark is my #2 favorite Netflix series",  "After Life is my #3 favorite Netflix series"]

因此,如果你需要arguments对象,你不能使用箭头函数。

但如果你真的想用一个箭头函数来复制同样的功能呢?你可以使用ES6剩余参数(...)。下面是你该如何重写你的函数:

const listYourFavNetflixSeries = (...seriesList) => {
   return seriesList.map( (series, i) => {
     return `${series} is my #${i +1} favorite Netflix series`
   } )
 }

总结

通过使用箭头函数,你可以编写带有隐式返回的单行代码,以解决JavaScript中this关键字的绑定问题。箭头函数在数组方法中也很好用,如.map().sort().forEach().filter()、和.reduce()。但请记住:箭头函数并不能取代常规的JavaScript函数。记住,只有当箭形函数是正确的工具时,才能使用它。

以上就是本文的所有内容,如果对你有所帮助,欢迎点赞收藏转发~

原文链接:www.sitepoint.com/arrow-funct…

作者:Maria Antonietta Perna

【推荐学习:javascript视频教程

以上是一文帶你了解JS箭頭函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:掘金社区。如有侵權,請聯絡admin@php.cn刪除
JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:學習曲線和易用性Python vs. JavaScript:學習曲線和易用性Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器