首页 > web前端 > js教程 > 箭头在JavaScript中的功能:脂肪与简洁语法

箭头在JavaScript中的功能:脂肪与简洁语法

尊渡假赌尊渡假赌尊渡假赌
发布: 2025-02-09 12:03:18
原创
936 人浏览过

Arrow Functions in JavaScript: Fat & Concise Syntax

深入了解JavaScript箭头函数。我们将向您展示如何使用ES6箭头语法,以及在代码中使用箭头函数时需要注意的一些常见错误。您将看到许多说明其工作原理的示例。

ECMAScript 2015(也称为ES6)发布后,JavaScript箭头函数随之出现。由于其简洁的语法和对this关键字的处理方式,箭头函数迅速成为开发人员最喜欢的功能之一。

关键要点

  • 箭头函数通过消除function关键字、花括号{}以及只有一个表达式时的return关键字,在JavaScript中提供了简洁的语法。
  • 对于单参数函数,可以省略箭头函数参数中的括号,但对于无参数或多参数函数以及使用默认参数时,则必须使用括号。
  • 箭头函数本质上是匿名的,这意味着它们没有名称标识符,但是当赋值给变量时,可以从变量推断出函数名称以用于调试。
  • 箭头函数中的this关键字捕获其值来自定义箭头函数的封闭上下文,而不是其被调用的位置,这使其适用于传统函数表达式需要绑定到外部this上下文的情况。
  • 箭头函数并不适用于所有情况,尤其是在对象的方法中或使用function构造函数时,因为它们具有词法this绑定并且缺少arguments对象。
  • 当将箭头函数与数组方法(如.map().sort().forEach().filter().reduce())一起使用时,它们可以增强可读性和简洁性,但必须注意确保它们是在特定上下文中适合这项工作的正确工具。

箭头函数语法:重写常规函数

函数就像食谱,您可以在其中存储有用的指令来完成程序中需要发生的事情,例如执行操作或返回值。通过调用您的函数,您可以执行食谱中包含的步骤。每次调用该函数时,您都可以这样做,而无需一遍遍地重写食谱。

以下是声明函数并在JavaScript中调用它的标准方法:

// 函数声明
function sayHiStranger() {
  return 'Hi, stranger!'
}

// 调用函数
sayHiStranger()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

您也可以将相同的函数编写为函数表达式,如下所示:

const sayHiStranger = function () {
  return 'Hi, stranger!'
}
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

JavaScript箭头函数始终是表达式。以下是如何使用胖箭头表示法将上面的函数重写为箭头函数表达式:

const sayHiStranger = () => 'Hi, stranger'
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

其优点包括:

  • 只需一行代码
  • 没有function关键字
  • 没有return关键字
  • 没有花括号{}

在JavaScript中,函数是“一等公民”。您可以将函数存储在变量中,将它们作为参数传递给其他函数,并将其作为值从其他函数返回。您可以使用JavaScript箭头函数执行所有这些操作。

无括号语法

在上面的示例中,函数没有参数。在这种情况下,您必须在胖箭头(=>)符号之前添加一组空括号()。当您创建具有多个参数的函数时,情况也是如此:

// 函数声明
function sayHiStranger() {
  return 'Hi, stranger!'
}

// 调用函数
sayHiStranger()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

但是,只有一个参数时,您可以省略括号(不必这样做,但可以):

const sayHiStranger = function () {
  return 'Hi, stranger!'
}
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

但是要小心。例如,如果您决定使用默认参数,则必须将其括在括号中:

const sayHiStranger = () => 'Hi, stranger'
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

仅仅因为您可以,并不意味着您应该这样做。伴随着一些轻松愉快的、善意的讽刺,Kyle Simpson(《你不知道JS》的作者)将他关于省略括号的想法放入了这个流程图中。(此处应插入流程图,但由于无法直接插入图片,此处省略)

隐式返回

当函数体中只有一个表达式时,您可以使ES6箭头语法更加简洁。您可以将所有内容都放在一行上,删除花括号,并去掉return关键字。

您刚才已经看到了这些简洁的一行代码是如何在上面的示例中工作的。再举一个例子,仅供参考。orderByLikes()函数的功能正如其名:它返回一个按点赞数最高的顺序排列的Netflix系列对象数组:

const getNetflixSeries = (seriesName, releaseDate) => `The ${seriesName} series was released in ${releaseDate}`
// 调用函数
console.log(getNetflixSeries('Bridgerton', '2020') )
// 输出:The Bridgerton series was released in 2020
登录后复制
登录后复制
登录后复制
登录后复制

这很酷,但是要注意代码的可读性——尤其是在使用一行代码和无括号ES6箭头语法对一堆箭头函数进行排序时,例如在此示例中:

const favoriteSeries = seriesName => seriesName === "Bridgerton" ? "Let's watch it" : "Let's go out"
// 调用函数
console.log(favoriteSeries("Bridgerton"))
// 输出:"Let's watch it"
登录后复制
登录后复制
登录后复制
登录后复制

那里发生了什么?尝试使用常规函数语法:

// 使用括号:正确
const bestNetflixSeries = (seriesName = "Bridgerton") => `${seriesName} is the best`
// 输出:"Bridgerton is the best"
console.log(bestNetflixSeries())

// 没有括号:错误
const bestNetflixSeries = seriesName = "Bridgerton" => `${seriesName} is the best`
// Uncaught SyntaxError: invalid arrow-function arguments (parentheses around the arrow-function may help)
登录后复制
登录后复制
登录后复制
登录后复制

现在,您可以快速了解外部函数greeter如何具有一个参数greeting,并返回一个匿名函数。反过来,这个内部函数又有一个名为name的参数,并使用greeting和name的值返回一个字符串。以下是如何调用该函数:

// 使用JS sort()函数按点赞数降序排列标题(点赞数越多,排名越高,点赞数越少,排名越低)
const orderByLikes = netflixSeries.sort( (a, b) => b.likes - a.likes )

// 调用函数
// 输出:按降序排列的标题和点赞数
console.log(orderByLikes)
登录后复制
登录后复制
登录后复制

注意这些隐式返回错误

当您的JavaScript箭头函数包含多个语句时,您需要将所有语句都括在花括号中并使用return关键字。

在下面的代码中,该函数构建一个包含一些Netflix系列标题和摘要的对象(Netflix评论来自烂番茄网站):

const greeter = greeting => name => `${greeting}, ${name}!`
登录后复制

.map()函数内的箭头函数通过一系列语句展开,最后返回一个对象。这使得在函数体周围使用花括号不可避免。

此外,由于您使用的是花括号,因此隐式返回不是一种选择。您必须使用return关键字。

如果您的函数使用隐式返回返回对象字面量,则需要将对象括在圆括号中。如果不这样做,将导致错误,因为JavaScript引擎错误地将对象字面量的花括号解析为函数的花括号。正如您刚才在上面注意到的那样,当您在箭头函数中使用花括号时,您不能省略return关键字。

前面代码的较短版本演示了此语法:

// 函数声明
function sayHiStranger() {
  return 'Hi, stranger!'
}

// 调用函数
sayHiStranger()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

您无法命名箭头函数

function关键字和参数列表之间没有名称标识符的函数称为匿名函数。以下是常规匿名函数表达式的外观:

const sayHiStranger = function () {
  return 'Hi, stranger!'
}
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

箭头函数都是匿名函数:

const sayHiStranger = () => 'Hi, stranger'
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

从ES6开始,变量和方法可以根据其句法位置推断匿名函数的名称,使用其name属性。这使得在检查其值或报告错误时可以识别该函数。

使用anonymousArrowFunc检查一下:

const getNetflixSeries = (seriesName, releaseDate) => `The ${seriesName} series was released in ${releaseDate}`
// 调用函数
console.log(getNetflixSeries('Bridgerton', '2020') )
// 输出:The Bridgerton series was released in 2020
登录后复制
登录后复制
登录后复制
登录后复制

请注意,此推断的name属性仅在匿名函数分配给变量时才存在,如上面的示例所示。如果您将匿名函数用作回调函数,则会失去此实用功能。下面的演示说明了这一点,其中.setInterval()方法中的匿名函数无法使用name属性:

const favoriteSeries = seriesName => seriesName === "Bridgerton" ? "Let's watch it" : "Let's go out"
// 调用函数
console.log(favoriteSeries("Bridgerton"))
// 输出:"Let's watch it"
登录后复制
登录后复制
登录后复制
登录后复制

而且不止如此。此推断的name属性仍然不能用作您可以从函数内部引用该函数的适当标识符——例如用于递归、取消绑定事件等。

箭头函数的内在匿名性导致Kyle Simpson表达了他对它们的看法如下:

由于我认为匿名函数不适合经常在程序中使用,所以我并不喜欢使用=>箭头函数形式。——《你不知道JS》

箭头函数如何处理this关键字

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

为了说明这意味着什么,请查看下面的演示:(此处应插入代码Pen,但由于无法直接插入代码Pen,此处省略)

这是一个按钮。单击按钮会触发从5到1的反向计数器,该计数器显示在按钮本身上。

// 使用括号:正确
const bestNetflixSeries = (seriesName = "Bridgerton") => `${seriesName} is the best`
// 输出:"Bridgerton is the best"
console.log(bestNetflixSeries())

// 没有括号:错误
const bestNetflixSeries = seriesName = "Bridgerton" => `${seriesName} is the best`
// Uncaught SyntaxError: invalid arrow-function arguments (parentheses around the arrow-function may help)
登录后复制
登录后复制
登录后复制
登录后复制

请注意.addEventListener()方法中的事件处理程序是如何一个常规匿名函数表达式,而不是箭头函数。为什么?如果您在函数内部记录this,您将看到它引用了已附加侦听器的按钮元素,这正是预期的结果,也是程序按计划工作所需的。

// 使用JS sort()函数按点赞数降序排列标题(点赞数越多,排名越高,点赞数越少,排名越低)
const orderByLikes = netflixSeries.sort( (a, b) => b.likes - a.likes )

// 调用函数
// 输出:按降序排列的标题和点赞数
console.log(orderByLikes)
登录后复制
登录后复制
登录后复制

在Firefox开发者工具控制台中,它的外观如下:(此处应插入图片,但由于无法直接插入图片,此处省略)

但是,尝试将常规函数替换为箭头函数,如下所示:

// 函数声明
function sayHiStranger() {
  return 'Hi, stranger!'
}

// 调用函数
sayHiStranger()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

现在,this不再引用按钮了。相反,它引用了Window对象:(此处应插入图片,但由于无法直接插入图片,此处省略)

这意味着,如果您想在单击按钮后使用this向按钮添加一个类,您的代码将无法工作,如下例所示:

const sayHiStranger = function () {
  return 'Hi, stranger!'
}
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

控制台中的错误消息如下:(此处应插入图片,但由于无法直接插入图片,此处省略)

当您在JavaScript中使用箭头函数时,this关键字的值不会重新绑定。它继承自父作用域(这称为词法作用域)。在此特定情况下,所讨论的箭头函数作为参数传递给startBtn.addEventListener()方法,该方法位于全局作用域中。因此,函数处理程序中的this也绑定到全局作用域——即Window对象。

因此,如果您希望this引用程序中的启动按钮,正确的方法是使用常规函数,而不是箭头函数。

匿名箭头函数

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

请注意,如果您使用常规函数,this的值将是什么:

const sayHiStranger = () => 'Hi, stranger'
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

它会是按钮元素吗?根本不会。它将是Window对象!(此处应插入图片,但由于无法直接插入图片,此处省略)

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

在这种情况下,一种常见的技巧是包含另一个变量来存储this关键字的值,以便它继续引用预期的元素——在本例中为按钮元素:

const getNetflixSeries = (seriesName, releaseDate) => `The ${seriesName} series was released in ${releaseDate}`
// 调用函数
console.log(getNetflixSeries('Bridgerton', '2020') )
// 输出:The Bridgerton series was released in 2020
登录后复制
登录后复制
登录后复制
登录后复制

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

const favoriteSeries = seriesName => seriesName === "Bridgerton" ? "Let's watch it" : "Let's go out"
// 调用函数
console.log(favoriteSeries("Bridgerton"))
// 输出:"Let's watch it"
登录后复制
登录后复制
登录后复制
登录后复制

使用箭头函数,问题完全消失了。以下是使用箭头函数时this的值:

// 使用括号:正确
const bestNetflixSeries = (seriesName = "Bridgerton") => `${seriesName} is the best`
// 输出:"Bridgerton is the best"
console.log(bestNetflixSeries())

// 没有括号:错误
const bestNetflixSeries = seriesName = "Bridgerton" => `${seriesName} is the best`
// Uncaught SyntaxError: invalid arrow-function arguments (parentheses around the arrow-function may help)
登录后复制
登录后复制
登录后复制
登录后复制

(此处应插入图片,但由于无法直接插入图片,此处省略)

这次,控制台记录了按钮,这就是我们想要的。事实上,程序将更改按钮文本,因此它需要this来引用按钮元素:

// 使用JS sort()函数按点赞数降序排列标题(点赞数越多,排名越高,点赞数越少,排名越低)
const orderByLikes = netflixSeries.sort( (a, b) => b.likes - a.likes )

// 调用函数
// 输出:按降序排列的标题和点赞数
console.log(orderByLikes)
登录后复制
登录后复制
登录后复制

箭头函数没有自己的this上下文。它们继承自父级的this值,正是由于此功能,它们才成为在上述情况下的绝佳选择。

JavaScript箭头函数并不总是正确的工具

箭头函数不仅仅是编写JavaScript函数的一种花哨的新方法。它们有其自身的局限性,这意味着有些情况下您不希望使用它。前面的演示中的点击处理程序就是一个例子,但这并不是唯一的一个。让我们再检查几个。

箭头函数作为对象方法

箭头函数不能很好地用作对象的方法。这是一个例子。

考虑这个netflixSeries对象,它有一些属性和几个方法。调用console.log(netflixSeries.getLikes())应该打印一条包含当前点赞数的消息,调用console.log(netflixSeries.addLike())应该将点赞数增加一,然后在控制台中打印新值和感谢消息:

// 函数声明
function sayHiStranger() {
  return 'Hi, stranger!'
}

// 调用函数
sayHiStranger()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

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

同样,问题在于箭头函数的词法作用域。对象方法中的this正在引用父作用域,在本例中是Window对象,而不是父对象本身——即不是netflixSeries对象。

当然,解决方案是使用常规函数:

const sayHiStranger = function () {
  return 'Hi, stranger!'
}
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

使用第三方库的箭头函数

另一个需要注意的是,第三方库通常会绑定方法调用,以便this值指向有用的内容。

例如,在jQuery事件处理程序中,this将允许您访问已绑定处理程序的DOM元素:

const sayHiStranger = () => 'Hi, stranger'
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

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

const getNetflixSeries = (seriesName, releaseDate) => `The ${seriesName} series was released in ${releaseDate}`
// 调用函数
console.log(getNetflixSeries('Bridgerton', '2020') )
// 输出:The Bridgerton series was released in 2020
登录后复制
登录后复制
登录后复制
登录后复制

这是一个使用Vue的进一步示例:

const favoriteSeries = seriesName => seriesName === "Bridgerton" ? "Let's watch it" : "Let's go out"
// 调用函数
console.log(favoriteSeries("Bridgerton"))
// 输出:"Let's watch it"
登录后复制
登录后复制
登录后复制
登录后复制

created钩子中,this绑定到Vue实例,因此显示“Hello, World!”消息。

但是,如果我们使用箭头函数,this将指向父作用域,该作用域没有message属性:

// 使用括号:正确
const bestNetflixSeries = (seriesName = "Bridgerton") => `${seriesName} is the best`
// 输出:"Bridgerton is the best"
console.log(bestNetflixSeries())

// 没有括号:错误
const bestNetflixSeries = seriesName = "Bridgerton" => `${seriesName} is the best`
// Uncaught SyntaxError: invalid arrow-function arguments (parentheses around the arrow-function may help)
登录后复制
登录后复制
登录后复制
登录后复制

箭头函数没有arguments对象

有时,您可能需要创建一个具有不确定数量参数的函数。例如,假设您想创建一个按偏好顺序列出您最喜欢的Netflix系列的函数。但是,您还不知道您要包含多少个系列。JavaScript提供了arguments对象。这是一个类似数组的对象(不是完整的数组),它存储在调用函数时传递给函数的值。

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

// 函数声明
function sayHiStranger() {
  return 'Hi, stranger!'
}

// 调用函数
sayHiStranger()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

当您调用该函数时,您将收到以下错误消息:Uncaught ReferenceError: arguments is not defined。这意味着arguments对象在箭头函数中不可用。事实上,将箭头函数替换为常规函数可以解决问题:

const sayHiStranger = function () {
  return 'Hi, stranger!'
}
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

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

但是,如果您真的想使用箭头函数来复制相同的功能呢?您可以做的一件事是使用ES6剩余参数(...)。以下是如何重写您的函数:

const sayHiStranger = () => 'Hi, stranger'
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

结论

通过使用箭头函数,您可以编写简洁的一行代码,使用隐式返回,并最终忘记使用旧方法来解决JavaScript中this关键字的绑定问题。箭头函数也与.map().sort().forEach().filter().reduce()等数组方法配合得很好。但请记住:箭头函数不会替换常规JavaScript函数。请记住,只有在箭头函数是正确的工具时才使用它们。

如果您对箭头函数有任何疑问,或者需要任何帮助来正确使用它们,我建议您访问SitePoint友好的论坛。那里有很多知识渊博的程序员随时准备提供帮助。

关于JavaScript箭头函数的常见问题

JavaScript中的箭头函数是什么?

您可以使用以下语法定义箭头函数:(参数)=>表达式。例如:(x,y)=>x y定义一个箭头函数,该函数接受两个参数并返回它们的和。

如何定义箭头函数?

您可以使用以下语法定义箭头函数:(参数)=>表达式。例如:(x,y)=>x y定义一个箭头函数,该函数接受两个参数并返回它们的和。

箭头函数和常规函数有什么区别?

箭头函数与常规函数在以下几个方面有所不同: 它们没有自己的this。相反,它们继承周围词法作用域的this值。 箭头函数不能用作构造函数,这意味着您不能使用new创建对象的实例。 箭头函数没有自己的arguments对象。相反,它们继承封闭作用域的arguments。 箭头函数更简洁,更适合简单的单行操作。

使用箭头函数的优点是什么?

箭头函数提供简洁的语法,使您的代码更具可读性。它们还有助于避免this绑定的问题,因为它们继承周围的上下文。这可以简化某些编码模式并减少对bindapplycall等变通方法的需求。

箭头函数适用于所有情况吗?

虽然箭头函数对许多场景很有用,但它们可能并不适用于所有情况。它们最适合短小简单的函数。对于复杂的函数或需要其自身this上下文的函数,传统函数可能更合适。

哪些JavaScript版本支持箭头函数?

箭头函数是在ECMAScript 6(ES6)中引入的,并受现代浏览器和Node.js版本支持。它们广泛用于现代JavaScript开发中。

箭头函数的局限性是什么?

箭头函数不能用作构造函数,没有自己的arguments对象,并且不太适合需要动态this上下文的方法。此外,它们的简洁语法可能不适合包含多个语句的函数。

箭头函数可以用于对象或类中的方法吗?

是的,箭头函数可以用于对象或类中的方法。但是,请记住,箭头函数没有自己的this,因此它们在需要动态this上下文的方法中可能不会按预期工作。

如何从箭头函数返回对象字面量?

当直接从箭头函数返回对象字面量时,需要将对象括在括号中,以避免与函数块混淆。例如:() => ({ key: value })。

我可以在箭头函数中为单个参数省略括号吗?

是的,如果箭头函数接受单个参数,则可以省略参数周围的括号。例如,x => x * 2是一个有效的箭头函数。

以上是箭头在JavaScript中的功能:脂肪与简洁语法的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板