This article can let you know all about JavaScript arrow functions. We’ll show you how to use ES6’s arrow syntax, as well as some common mistakes to watch out for when using arrow functions in your code. You'll see lots of examples of how they work.
JavaScript’s arrow functions arrived with the release of ECMAScript 2015, also known as ES6. Due to their concise syntax and handling of the this keyword, arrow functions have quickly become a favorite feature among developers.
Functions are like recipes in which you store useful instructions to accomplish something you need to happen in your program, such as performing an action or return a value. By calling a function, you execute the steps contained in the recipe. You can do this every time you call the function without having to rewrite the recipe again and again.
Here's the standard way to declare a function and call it in JavaScript:
// function declaration function sayHiStranger() { return 'Hi, stranger!' } // call the function sayHiStranger()
You can also write the same function as a function expression, just like this:
const sayHiStranger = function () { return 'Hi, stranger!' }
JavaScript Arrow functions are always expressions. Here's how to rewrite the function above using arrow notation:
const sayHiStranger = () => 'Hi, stranger'
The benefits of doing this include:
function
Keywordsreturn
Keywords{}
In JavaScript, functions A first-class citizen. You can store functions in variables, pass them as arguments to other functions, and return them as values from other functions. You can use JavaScript arrow functions to do all of these things.
In the above example, the function has no parameters. In this case, you must add an empty pair of parentheses ()
before the fat arrow symbol (=>
). Same thing when there are multiple parameters:
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
If there is only one parameter, you can omit the parentheses (you don't have to, but you can):
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"
When you do Always be careful. For example, if you decide to use default parameters, you must wrap them in parentheses:
// 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)
When there is only one expression in the function body, You can make ES6's arrow syntax more concise. You can put everything on one line, remove the curly braces, and remove the return
keyword.
You've seen how these nifty one-liners work in the example above. The following orderByLikes()
function returns an array of Netflix episode objects, sorted by the highest number of likes:
// 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)
This way of writing is cool, but pay attention to the readability of the code. Especially when sorting through a bunch of arrow functions using single-line and bracketless ES6 arrow syntax. Like this example:
const greeter = greeting => name => `${greeting}, ${name}!`
What happened there? Try using the regular function syntax:
function greeter(greeting) { return function(name) { return `${greeting}, ${name}!` } }
Now you can quickly see how the external function greeter
has parameters greeting
, and returns an anonymous function. This inner function takes another parameter called name
and returns a string using the values of greeting
and name
. Here's how to call the function:
const myGreet = greeter('Good morning') console.log( myGreet('Mary') ) // output: "Good morning, Mary!"
When your JavaScript arrow function contains more than one statement, you need to wrap them all within curly braces statement and use the return
keyword.
In the following code, the function creates an object containing the titles and summaries of several Netflix episodes:
const seriesList = netflixSeries.map( series => { const container = {} container.title = series.name container.summary = series.summary // explicit return return container } )
.map()
in the function Arrow functions expand in a series of statements, returning an object at the end of the statement. This makes the use of braces around function bodies unavoidable.
Also, since curly braces are being used, implicit return is not an option. You must explicitly use the return
keyword.
If your function uses implicit return to return an object literal, you need to use parentheses to wrap the object literal. Failure to do so will result in an error because the JavaScript engine incorrectly parses the braces of an object literal as braces of a function. As you just noticed, when you use curly braces in an arrow function, you cannot omit the return
keyword.
A shorter version of the preceding code demonstrates this syntax:
// Uncaught SyntaxError: unexpected token: ':' const seriesList = netflixSeries.map(series => { title: series.name }); // Works fine const seriesList = netflixSeries.map(series => ({ title: series.name }));
in function
key Functions that have no name identifier between the word and parameter list are called anonymous functions. Here's what a regular anonymous function expression looks like:
const anonymous = function() { return 'You can\'t identify me!' }
Arrow functions are all anonymous functions:
const anonymousArrowFunc = () => 'You can\'t identify me!'
Starting with ES6, variables and methods can be passed through the syntax position of the anonymous function, using name
attribute to infer its name. This makes it possible to identify the function when checking its value or reporting an error.
Use anonymousArrowFunc
Check it out:
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
关键字不会重新绑定。
为了说明这意味着什么,请查看下面的演示。
这里有一个按钮。点击按钮会触发一个从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视频教程】
The above is the detailed content of This article will teach you about JS arrow functions. For more information, please follow other related articles on the PHP Chinese website!