本文可以讓你了解所有關於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
的參數,並且使用greeting
和name
的值回傳一個字串。以下是呼叫函數的方式:
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('click', function() { this.classList.add('counting') let counter = 5; const timer = setInterval(() => { this.textContent = counter counter -- if(counter < 0) { this.textContent = 'THE END!' this.classList.remove('counting') clearInterval(timer) } }, 1000) })
注意到.addEventListener()
方法里面的事件处理器是一个常规的匿名函数表达式,而不是一个箭头函数。为什么呢?如果在函数内部打印this
的值,你会看到它引用了监听器所连接的按钮元素,这正是我们所期望的,也是程序按计划工作所需要的:
startBtn.addEventListener('click', function() { console.log(this) ... })
下面是它在Firefox开发人员工具控制台中的样子:
然后,尝试使用箭头函数来替代常规函数,就像这样:
startBtn.addEventListener('click', () => { console.log(this) ... })
现在,this
不再引用按钮元素。相反,它引用Window
对象:
这意味着,如果你想要在按钮被点击之后,使用this
来为按钮添加class
,你的代码就无法正常工作:
// change button's border's appearance this.classList.add('counting')
下面是控制台中的错误信息:
当你在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)
这次,控制台打印了button
,这就是我们想要的。事实上,程序要改变按钮的文本,所以它需要this
来指代button
元素:
const timer = setInterval( () => { console.log(this) // the button'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: 'After Life', 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.title
和this.likes
未能分别引用对象的属性title
和likes
。
这次,问题出在箭头函数的词法作用域上。对象方法中的this
引用的是父对象的范围,在本例中是Window
对象,而不是父对象本身--也就是说,不是netflixSeries
对象。
当然,解决办法是使用常规函数:
const netflixSeries = { title: 'After Life', 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元素:
$('body').on('click', function() { console.log(this) }) // <body>
但是如果我们使用箭头函数,正如我们所看到的,它没有自己的this
上下文,我们会得到意想不到的结果:
$('body').on('click', () =>{ console.log(this) }) // Window
下面是使用Vue的其他例子:
new Vue({ el: app, data: { message: 'Hello, World!' }, created: function() { console.log(this.message); } }) // Hello, World!
在created
钩子内部,this
被绑定到Vue实例上,因此会显示'Hello, World!'
信息。
然而如果我们使用箭头函数,this
将会指向父作用域,上面没有message
属性:
new Vue({ el: app, data: { message: 'Hello, World!' }, 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('Bridgerton', 'Ozark', 'After Life'))
当你调用该函数时,你会得到以下错误: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('Bridgerton', 'Ozark', 'After Life')) // 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函数。记住,只有当箭形函数是正确的工具时,才能使用它。
以上就是本文的所有内容,如果对你有所帮助,欢迎点赞收藏转发~
【推荐学习:javascript视频教程】
以上是一文帶你了解JS箭頭函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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

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

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

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

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

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

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

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


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

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

Dreamweaver CS6
視覺化網頁開發工具

WebStorm Mac版
好用的JavaScript開發工具

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

記事本++7.3.1
好用且免費的程式碼編輯器