在这篇文章中,你将了解所有关于JavaScript的箭头函数语法--包括在代码中利用箭头函数时需要注意的一些问题。你会看到很多例子来说明它们是如何工作的。
箭头函数是随着ECMAScript 2015的发布而被引入JavaScript的,也被称为ES6。它们简洁的语法和处理*this*关键字的方式,是促使箭头函数在开发者中获得巨大成功的主要特征之一。
将ES6前的函数变成箭头函数
你可以把函数看作是一种食谱,在这里你可以存储有用的指令来完成你在程序中需要做的事情,比如执行一个动作或返回一个值。通过调用你的函数,你就执行了你的食谱中所包含的步骤,而且你可以在每次调用该函数时都这样做,而不需要一次又一次地重写该食谱。
这里有一个标准的方法来声明一个函数,然后在JavaScript中调用它。
// function declaration
function sayHiStranger() {
return 'Hi, stranger!'
}
// call the function
sayHiStranger()
你也可以把同一个函数写成一个函数表达式,像这样。
const sayHiStranger = function () {
return 'Hi, stranger!'
}
箭头函数总是表达式。下面是你如何使用胖箭头符号重写上面的函数。
const sayHiStranger = () => 'Hi, stranger'
这样做的好处包括。
- 只有一行代码
- 没有
function关键字 - 没有
return关键字 - 没有大括号{}。
在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)
仅仅因为你可以,并不意味着你应该。Kyle Simpson(《你不知道的JS》的作者)把他对省略小括号的想法写进了这个流程图中,其中夹杂着一点轻松、善意的讽刺。
隐式返回
当你的函数体中只有一个表达式时,你可以把所有东西放在一行,去掉大括号,并取消return 关键字。在上面的例子中,你已经看到了这些巧妙的单行代码是如何工作的。这里还有一个例子,只是为了更好地衡量。orderByLikes() 函数做了它所描述的事情:也就是说,它返回一个Netflix系列对象的数组,按喜欢的最高数量排序。
// 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)
这很酷,但要注意你的代码的可读性--特别是当使用单行和无括号语法对一堆箭头函数进行排序时,就像在这个例子中。
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!"
注意这些隐式返回的问题
当你的箭头函数包含一个以上的语句时,你需要用大括号把所有的语句包起来,并使用return 关键字。在下面的代码中,该函数建立了一个对象,包含几个Netflix系列的标题和摘要(Netflix的评论来自Rotten Tomatoes网站)。
const seriesList = netflixSeries.map( series => {
const container = {}
container.title = series.name
container.summary = series.summary
// explicit return
return container
} )
.map() 函数内的箭头函数在一系列的语句中发展,在结束时返回一个对象。这使得在函数的主体周围使用大括号是不可避免的。此外,由于你使用了大括号,隐式返回不是一个选项。你必须使用return 关键字。
如果你的箭头函数使用隐式返回返回一个对象字面,你需要将该对象包裹在圆括号内。不这样做会导致错误,因为JS引擎错误地将对象字面的大括号解析为函数的大括号。正如你刚刚注意到的,当你在一个箭头函数中使用大括号时,你不能省略返回关键字。
这种语法在前面代码的较短版本中进行了演示。
// 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 属性仍然不能作为一个适当的标识符,你可以用它来指代函数本身--比如递归、解除绑定事件等等。
箭头函数内在的匿名性使得Kyle Simpson对箭头函数表达了如下观点。
因为我认为匿名函数在你的程序中经常使用并不是一个好主意,所以我不喜欢使用
=>箭头函数的形式。-你不了解JS