深入了解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
关键字不会重新绑定。
为了说明这意味着什么,请查看下面的演示:(此处应插入代码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函数的一种花哨的新方法。它们有其自身的局限性,这意味着有些情况下您不希望使用它。前面的演示中的点击处理程序就是一个例子,但这并不是唯一的一个。让我们再检查几个。
箭头函数不能很好地用作对象的方法。这是一个例子。
考虑这个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.title
和this.likes
无法分别引用对象的属性title
和likes
。
同样,问题在于箭头函数的词法作用域。对象方法中的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)
有时,您可能需要创建一个具有不确定数量参数的函数。例如,假设您想创建一个按偏好顺序列出您最喜欢的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友好的论坛。那里有很多知识渊博的程序员随时准备提供帮助。
您可以使用以下语法定义箭头函数:(参数)=>表达式。例如:(x,y)=>x y定义一个箭头函数,该函数接受两个参数并返回它们的和。
您可以使用以下语法定义箭头函数:(参数)=>表达式。例如:(x,y)=>x y定义一个箭头函数,该函数接受两个参数并返回它们的和。
箭头函数与常规函数在以下几个方面有所不同:
它们没有自己的this
。相反,它们继承周围词法作用域的this
值。
箭头函数不能用作构造函数,这意味着您不能使用new
创建对象的实例。
箭头函数没有自己的arguments
对象。相反,它们继承封闭作用域的arguments
。
箭头函数更简洁,更适合简单的单行操作。
箭头函数提供简洁的语法,使您的代码更具可读性。它们还有助于避免this
绑定的问题,因为它们继承周围的上下文。这可以简化某些编码模式并减少对bind
、apply
或call
等变通方法的需求。
虽然箭头函数对许多场景很有用,但它们可能并不适用于所有情况。它们最适合短小简单的函数。对于复杂的函数或需要其自身this
上下文的函数,传统函数可能更合适。
箭头函数是在ECMAScript 6(ES6)中引入的,并受现代浏览器和Node.js版本支持。它们广泛用于现代JavaScript开发中。
箭头函数不能用作构造函数,没有自己的arguments
对象,并且不太适合需要动态this
上下文的方法。此外,它们的简洁语法可能不适合包含多个语句的函数。
是的,箭头函数可以用于对象或类中的方法。但是,请记住,箭头函数没有自己的this
,因此它们在需要动态this
上下文的方法中可能不会按预期工作。
当直接从箭头函数返回对象字面量时,需要将对象括在括号中,以避免与函数块混淆。例如:() => ({ key: value })。
是的,如果箭头函数接受单个参数,则可以省略参数周围的括号。例如,x => x * 2是一个有效的箭头函数。
以上是箭头在JavaScript中的功能:脂肪与简洁语法的详细内容。更多信息请关注PHP中文网其他相关文章!