JavaScript 中的箭头函数:如何使用简洁的语法

news2025/1/14 18:06:26

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

JavaScript 箭头函数随着 ECMAScript 2015(也称为 ES6)的发布而出现。由于其简洁的语法和对*this*关键字的处理,箭头函数很快成为开发人员最喜欢的功能。

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

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

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

// function declaration
function sayHiStranger() {
  return 'Hi, stranger!'
}

// call the function
sayHiStranger()

您还可以编写与函数表达式相同的函数,如下所示:

const sayHiStranger = function () {
  return 'Hi, stranger!'
}

JavaScript 箭头函数始终是表达式。以下是如何使用粗箭头符号重写上面的函数:

const sayHiStranger = () => 'Hi, stranger'

这样做的好处包括:

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

在 JavaScript 中,函数是“一等公民”。您可以将函数存储在变量中,将它们作为参数传递给其他函数,并将它们作为值从其他函数返回。您可以使用 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)

隐式回报

当函数体内只有一个表达式时,可以使 ES6 箭头语法更加简洁。您可以将所有内容保留在一行中,删除花括号,并取消关键字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)

这很酷,但请注意代码的可读性 - 特别是在使用单行代码和无括号的 ES6 箭头语法对一堆箭头函数进行排序时,如下例所示:

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!" 

注意这些隐式返回错误

当您的 JavaScript 箭头函数包含多个语句时,您需要将它们全部括在花括号中并使用关键字return

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

const seriesList = netflixSeries.map( series => {
  const container = {}
  container.title = series.name 
  container.summary = series.summary

  // explicit return
  return container
} )

函数内部的箭头函数.map()由一系列语句组成,在语句末尾返回一个对象。这使得在函数体周围使用花括号是不可避免的。

另外,当您使用花括号时,隐式返回不是一个选项。您必须使用return关键字。

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

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

// 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属性仍然不能作为一个正确的标识符,您可以使用它来从内部引用该函数——例如递归、解除绑定事件等。

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

关于箭头函数,要记住的最重要的事情是它们处理关键字的方式this。特别是,this箭头函数内的关键字不会反弹。

为了说明这意味着什么,请查看下面的演示:

[codepen_embed height=”300″ default_tab=”html,result” slug_hash=”qBqgBmR” user=”SitePoint”]在CodePen上通过 SitePoint ( @SitePoint )查看
箭头函数中的Pen JS this 。[/codepen_embed]

这是一个按钮。单击该按钮会触发从 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 开发者工具控制台中的内容如下:

处理按钮单击事件的常规匿名函数表达式内的 this 关键字的日志

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

startBtn.addEventListener('click', () => {
  console.log(this)
  ...
})

现在,this不再引用该按钮。相反,它引用该Window对象:

JavaScript 箭头函数内的 this 关键字引用的 window 对象传递给事件侦听器

这意味着,例如,如果您想this在单击按钮后向按钮添加类,您的代码将不起作用:

// 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对象!

在 setInterval() 中使用常规函数将 this 关键字的引用从按钮更改为 Window 对象

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

在这种情况下,一个常见的技巧是包含另一个变量来存储关键字的值,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)

传递给 setInterval() 的箭头函数内的 this 值

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

const timer = setInterval( () => { 
  console.log(this)
 // the button's text displays the timer value
  this.textContent = counter
}, 1000)

箭头函数没有自己的this上下文。他们继承了父母的价值this,正是因为这一特点,他们在上述情况下做出了很好的选择。

JavaScript 箭头函数并不总是适合该工作的工具

箭头函数不仅仅是在 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 Like undefine, it now has NaN likes”。因此,this.title和分别this.likes无法引用对象的属性titlelikes

问题再次出在箭头函数的词法范围上。对象的内部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!

在钩子内部createdthis绑定到 Vue 实例,因此“Hello, World!” 显示消息。

然而,如果我们使用箭头函数,this它将指向没有属性的父作用域message

new Vue({
  el: app,
  data: {
    message: 'Hello, World!'
  },
  created: function() {
    console.log(this.message);
  }
})
// undefined

箭头函数没有arguments对象

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

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

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`
   } )
 }

结论

通过使用箭头函数,您可以编写带有隐式返回的简洁单行代码,并最终忘记旧式技巧来解决thisJavaScript 中关键字的绑定。箭头函数也可以很好地与.map().sort().forEach().filter()和 等数组方法配合使用.reduce()。但请记住:箭头函数不会取代常规 JavaScript 函数。请记住,仅当 JavaScript 箭头函数是适合该工作的工具时才使用它们。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/944776.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【pyqt5界面化开发-4】垂直布局/水平布局+‘套娃‘布局

目录 一、垂直布局 二、布局器的组合 三、水平布局垂直布局&#xff08;套娃&#xff09; 一、垂直布局 需要模块&#xff1a;QVBoxLayout # 垂直布局layout QVBoxLayout()………………# 应用设置的布局器self.setLayout(layout) 模块间的伸缩器&#xff08;可以理解为弹簧…

InfluxDB在Windows的下载,安装,自启动

1.官网下载 官网下载地址&#xff0c;我一般都喜欢官网下载&#xff0c;包含windows&#xff0c;linux&#xff0c;macos&#xff0c;docker&#xff0c;K8s甚至树莓派系统等。 2.启动 进入到文件夹下&#xff0c;双击启动exe的话会一闪而过&#xff0c;它告诉你要cmd用命令…

uni-app中使用iconfont彩色图标

uni-app中使用iconfont彩色图标 大家好&#xff0c;今天我们来学习一下uni-app中使用iconfont彩色图标&#xff0c;好好看&#xff0c;好好学&#xff0c;超详细的 第一步 首先&#xff0c;从iconfont官网&#xff08;iconfont-阿里巴巴矢量图标库&#xff09;选择自己需要的图…

九号公司董事长高禄峰:立足科技创新,助力行业发展

从整个电动两轮车发展时间线来看&#xff0c;尽管九号公司2019年才正式进入局电动两轮车市场&#xff0c;但公司凭借智能化入局&#xff0c;在短短三年时间里&#xff0c;已经成长为智能电动两轮车市场的领军者&#xff0c;在这期间&#xff0c;九号公司既没有多年的市场积累&a…

基于 OV5640 摄像头理论知识讲解-典型工作模式配置

基于OV2640/ OV5640 的图像采集显示系统系列文章目录&#xff1a; &#xff08;1&#xff09;基于 OV5640 摄像头理论知识讲解-成像和采样原理 &#xff08;2&#xff09;基于 OV5640 摄像头理论知识讲解-数字接口和控制接口 &#xff08;3&#xff09;基于 OV5640 摄像头理论知…

单链表oj题

&#x1f35f;1.反转链表 链接: https://leetcode.cn/problems/reverse-linked-list/description/ 思路一&#xff1a;遍历一遍的同时两两逆置 写法一&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next…

生成式AI背景下编程工作者的技术和高级软考理论的演进融合之路

思考背景 近两次软考&#xff0c;我都参与了&#xff0c;2022年11月参加的是系统架构师的考试&#xff0c;2023年5月参加的是系统分析师的考试&#xff0c;去年参加系统架构是考试是完全的裸考和第一次考&#xff0c;成绩是选择题39&#xff0c;综合题46和论文48分&#xff0c…

开发卡牌gamefi游戏需要多少钱?

卡牌游戏作为一种受欢迎的游戏形式&#xff0c;吸引了众多开发者的关注。然而&#xff0c;开发一款成功的卡牌游戏需要全面考虑多个方面的因素&#xff0c;其中之一就是资金投入。本文将从专业性和投入回报的角度&#xff0c;探讨开发一款卡牌游戏所需的资金投入。 一、专业性的…

[Agent]开发---csvAgent开发

资料&#xff1a; https://python.langchain.com/docs/integrations/toolkits/csvcsvagent需要csv文件和模型&#xff0c;该方法在后台使用pandas方法去处理该文件&#xff0c;然后调用LLM去回答问题 我们使用内置函数去调用csvagent。 AgentType根据自己需要下载&#xff1b;…

国家公派必读|CSC各类留学人员奖学金资助和艰苦地区补贴标准

国家留学基金委&#xff08;以下简称CSC&#xff09;为公派留学人员&#xff08;含高级研究人员、访问学者、博士后及留学生&#xff09;提供一定数额的奖学金&#xff0c;对艰苦地区还有特殊生活补贴&#xff0c;本文知识人网小编根据相关文件加以整理后撰文如下。 根据以上文…

打破对ChatGPT的依赖以及如何应对ChatGPT的错误和幻觉

​ OpenAI的ChatGPT是第一个真正流行的生成式AI工具&#xff0c;但它可能不是最好的。现在是时候扩大你的AI视野了。 ChatGPT成为了基于大语言模型(LLM)的聊天机器人的同义词。但是现在是时候停止对ChatGPT的痴迷&#xff0c;开始发现这个新世界中强大的替代品了。 首先&a…

StringBuilder类分享(1)

一、StringBuilder说明 StringBuilder是一个可变的字符序列。这个类提供了一个与StringBuffer兼容的API&#xff0c;但不保证同步&#xff0c;即StringBuilder不是线程安全的&#xff0c;而StringBuffer是线程安全的。显然&#xff0c;StringBuilder要运行的更快一点。 这个类…

编程题四大算法思想(一)——分治法:最大子数组问题、矩阵乘法的Strassen算法、最近点对问题、凸包问题

文章目录 分治法分治策略分治算法的效率分析归并排序 具体应用问题最大子数组问题蛮力法分治法找跨越中间位置的最大子数组时间复杂度 矩阵乘法蛮力算法分治法Strassen矩阵乘法 分治法 方法 分治策略分治法效率分析——迭代法&#xff08;递归树法&#xff09;分治法效率分析—…

学习JAVA打卡第四十六天

Date和Calendar类 Date类 ⑴使用无参数构造方法 使用Date 类的无参数构造方法创建的对象可以获取本机的当前日期和时间&#xff0c;例如&#xff1a; Date nowtime new Date&#xff08;&#xff09;&#xff1b; ⑵使用带参数的构造方法 计算机系统将其自身的时间的设“…

redis实战-项目集成git及redis实现短信验证码登录

目录 IDEA集成git 传统session存在的问题 redis方案 业务流程 选用的数据结构 整体访问流程 发送短信验证码 获取校验验证码 配置登录拦截器 拦截器注册配置类 拦截器 用户状态刷新问题 刷新问题解决方案 IDEA集成git 远程仓库采用码云&#xff0c;创建好仓库&…

js定位到元素底部

文字的一行一行添加的&#xff0c;每次添加要滚动条自动定位到元素底部 <div class"An">//要父元素包裹&#xff0c;父元素设置max-height&#xff0c;overflow啥的<div class"friendly_pW"></div></div>//添加文字时找子元素的高…

数据管理,是企业管理的上帝视角

在早期&#xff0c;企业整体规模较小&#xff0c;市场以及产品也比较匮乏&#xff0c;用户对商品没有过多的需求&#xff0c;更多是出于对必需品的需要&#xff0c;选择购买商品。伴随着经济的飞速发展&#xff0c;企业规模在扩大的同时&#xff0c;市场和用户对商品的需求日益…

【pyqt5界面化工具开发-8】窗口开发-QDialog对话框

目录 一、调用父类的菜单 二、添加更多的布局在对话框内 一、调用父类的菜单 和前面Qwedget一样的结构&#xff08;不做过多介绍&#xff09; 可以参考代码中的注释 import sys from PyQt5.QtWidgets import QApplication, QPushButton, QDialog# 对话框&#xff08;多运用…

Windows服务器使用Mysqldump备份MySQL数据库方法

Windows服务器使用Mysqldump备份MySQL数据库方法 1.进入到MySQL安装目录的bin目录下&#xff0c;进入cmd F:\20220601\dev_software\mysql-8.0.11-winx64 2.执行备份命令&#xff1a; mysqldump -u root -p zj_bak test_bak -r D:\backup.sql3.导入备份 数据&#xff1a; m…