JavaScript箭头函数语法的详细指南

345 阅读6分钟

在这篇文章中,你将了解所有关于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 的参数,并使用greetingname 的值返回一个字符串。 这里是你如何调用这个函数的。

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

继续阅读JavaScript 箭头函数。胖子和简明的语法SitePoint上。