目录
箭头函数语法
无圆括号语法
隐式返回
注意隐式返回错误
无法命名箭头函数
如何处理this关键字
匿名箭头函数
不正常工作的情况
箭头函数作为对象方法
箭头函数与第三方库
箭头函数没有arguments对象
总结
首页 web前端 js教程 一文带你了解JS箭头函数

一文带你了解JS箭头函数

Nov 10, 2022 pm 03:58 PM
javascript 箭头函数

一文带你了解JS箭头函数

本文可以让你了解所有有关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()函数返回奈飞剧集对象的数组,按照最高点赞数排序:

// 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的参数,并使用greetingname的值返回一个字符串。下面是调用函数的方式:

const myGreet = greeter('Good morning')
console.log( myGreet('Mary') )   

// output: 
"Good morning, Mary!"
登录后复制

注意隐式返回错误

当你的JavaScript箭头函数包含不止一个语句,你需要在大括号内包裹所有语句,并使用return关键字。

在下面的代码中,该函数建立了一个包含几个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关键字不会重新绑定。

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

这里有一个按钮。点击按钮会触发一个从5到1的反向计数器,它显示在按钮本身。

<button class="start-btn">Start Counter</button>

...

const startBtn = document.querySelector(".start-btn");

startBtn.addEventListener(&#39;click&#39;, function() {
  this.classList.add(&#39;counting&#39;)
  let counter = 5;
  const timer = setInterval(() => {
    this.textContent = counter 
    counter -- 
    if(counter < 0) {
      this.textContent = &#39;THE END!&#39;
      this.classList.remove(&#39;counting&#39;)
      clearInterval(timer)
    }
  }, 1000) 
})
登录后复制

注意到.addEventListener()方法里面的事件处理器是一个常规的匿名函数表达式,而不是一个箭头函数。为什么呢?如果在函数内部打印this的值,你会看到它引用了监听器所连接的按钮元素,这正是我们所期望的,也是程序按计划工作所需要的:

startBtn.addEventListener(&#39;click&#39;, function() {
  console.log(this)
  ...
})
登录后复制

下面是它在Firefox开发人员工具控制台中的样子:

image.png

然后,尝试使用箭头函数来替代常规函数,就像这样:

startBtn.addEventListener(&#39;click&#39;, () => {
  console.log(this)
  ...
})
登录后复制

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

image.png

这意味着,如果你想要在按钮被点击之后,使用this来为按钮添加class,你的代码就无法正常工作:

// change button&#39;s border&#39;s appearance
this.classList.add(&#39;counting&#39;)
登录后复制

下面是控制台中的错误信息:

image.png

当你在JavaScript中使用箭头函数,this关键字的值不会被重新绑定。它继承自父作用域(也称为词法作用域)。在这种特殊情况下,箭头函数被作为参数传递给startBtn.addEventListener()方法,该方法位于全局作用域中。因此,函数处理器中的this也被绑定到全局作用域中--也就是Window对象。

因此,如果你想让this引用程序中的开始按钮,正确的做法是使用一个常规函数,而不是一个箭头函数。

匿名箭头函数

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

请注意,如果你使用常规函数,this值会是多少:

const timer = setInterval(function() {
  console.log(this)
  ...
}, 1000)
登录后复制

button元素吗?并不是。这个值将会是Window对象!

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

在这种情况下,一个常见的hack手段是包括另一个变量来存储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)
登录后复制

set-interval-correct-log.png

这次,控制台打印了button,这就是我们想要的。事实上,程序要改变按钮的文本,所以它需要this来指代button元素:

const timer = setInterval( () => { 
  console.log(this)
 // the button&#39;s text displays the timer value
  this.textContent = counter
}, 1000)
登录后复制

箭头函数没有自己的this上下文。它们从父级继承this的值,正是因为这个特点,在上面这种情况下就是很好的选择。

不正常工作的情况

箭头函数并不只是在JavaScript中编写函数的一种花里胡哨的新方法。它们有自己的局限性,这意味着在有些情况下你不想使用箭头函数。让我们看看更多的例子。

箭头函数作为对象方法

箭头函数作为对象上的方法不能很好地工作。

考虑这个netflixSeries对象,上面有一些属性和一系列方法。调用console.log(netflixSeries.getLikes()) 应该会打印一条信息,说明当前喜欢的人数。console.log(netflixSeries.addLike())应该会增加一个喜欢的人数,然后在控制台上打印新值:

const netflixSeries = {
  title: &#39;After Life&#39;, 
  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()方法返回&#39;undefined has NaN likes&#39;,调用.addLike()方法返回&#39;Thank you for liking undefined, which now has NaN likes&#39;。因此,this.titlethis.likes未能分别引用对象的属性titlelikes

这次,问题出在箭头函数的词法作用域上。对象方法中的this引用的是父对象的范围,在本例中是Window对象,而不是父对象本身--也就是说,不是netflixSeries对象。

当然,解决办法是使用常规函数:

const netflixSeries = {
  title: &#39;After Life&#39;, 
  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元素:

$(&#39;body&#39;).on(&#39;click&#39;, function() {
  console.log(this)
})
// <body>
登录后复制

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

$(&#39;body&#39;).on(&#39;click&#39;, () =>{
  console.log(this)
})
// Window
登录后复制

下面是使用Vue的其他例子:

new Vue({
  el: app,
  data: {
    message: &#39;Hello, World!&#39;
  },
  created: function() {
    console.log(this.message);
  }
})
// Hello, World!
登录后复制

created钩子内部,this被绑定到Vue实例上,因此会显示&#39;Hello, World!&#39;信息。

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

new Vue({
  el: app,
  data: {
    message: &#39;Hello, World!&#39;
  },
  created: () => {
    console.log(this.message);
  }
})
// undefined
登录后复制

箭头函数没有arguments对象

有时,你可能需要创建一个具有无限参数个数的函数。比如,假设你想创建一个函数,列出你最喜欢的奈飞剧集,并按照偏好排序。然而,你还不知道你要包括多少个剧集。JavaScript提供了arguments对象。这是一个类数组对象(不是完整的数组),在调用时存储传递给函数的值。

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

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(&#39;Bridgerton&#39;, &#39;Ozark&#39;, &#39;After Life&#39;))
登录后复制

当你调用该函数时,你会得到以下错误: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(&#39;Bridgerton&#39;, &#39;Ozark&#39;, &#39;After Life&#39;))

// 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`
   } )
 }
登录后复制

总结

通过使用箭头函数,你可以编写带有隐式返回的单行代码,以解决JavaScript中this关键字的绑定问题。箭头函数在数组方法中也很好用,如.map().sort().forEach().filter()、和.reduce()。但请记住:箭头函数并不能取代常规的JavaScript函数。记住,只有当箭形函数是正确的工具时,才能使用它。

以上就是本文的所有内容,如果对你有所帮助,欢迎点赞收藏转发~

原文链接:www.sitepoint.com/arrow-funct…

作者:Maria Antonietta Perna

【推荐学习:javascript视频教程

以上是一文带你了解JS箭头函数的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何使用WebSocket和JavaScript实现在线语音识别系统 如何使用WebSocket和JavaScript实现在线语音识别系统 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript实现在线语音识别系统引言:随着科技的不断发展,语音识别技术已经成为了人工智能领域的重要组成部分。而基于WebSocket和JavaScript实现的在线语音识别系统,具备了低延迟、实时性和跨平台的特点,成为了一种被广泛应用的解决方案。本文将介绍如何使用WebSocket和JavaScript来实现在线语音识别系

WebSocket与JavaScript:实现实时监控系统的关键技术 WebSocket与JavaScript:实现实时监控系统的关键技术 Dec 17, 2023 pm 05:30 PM

WebSocket与JavaScript:实现实时监控系统的关键技术引言:随着互联网技术的快速发展,实时监控系统在各个领域中得到了广泛的应用。而实现实时监控的关键技术之一就是WebSocket与JavaScript的结合使用。本文将介绍WebSocket与JavaScript在实时监控系统中的应用,并给出代码示例,详细解释其实现原理。一、WebSocket技

如何利用JavaScript和WebSocket实现实时在线点餐系统 如何利用JavaScript和WebSocket实现实时在线点餐系统 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket实现实时在线点餐系统介绍:随着互联网的普及和技术的进步,越来越多的餐厅开始提供在线点餐服务。为了实现实时在线点餐系统,我们可以利用JavaScript和WebSocket技术。WebSocket是一种基于TCP协议的全双工通信协议,可以实现客户端与服务器的实时双向通信。在实时在线点餐系统中,当用户选择菜品并下单

如何使用WebSocket和JavaScript实现在线预约系统 如何使用WebSocket和JavaScript实现在线预约系统 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript实现在线预约系统在当今数字化的时代,越来越多的业务和服务都需要提供在线预约功能。而实现一个高效、实时的在线预约系统是至关重要的。本文将介绍如何使用WebSocket和JavaScript来实现一个在线预约系统,并提供具体的代码示例。一、什么是WebSocketWebSocket是一种在单个TCP连接上进行全双工

JavaScript和WebSocket:打造高效的实时天气预报系统 JavaScript和WebSocket:打造高效的实时天气预报系统 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的实时天气预报系统引言:如今,天气预报的准确性对于日常生活以及决策制定具有重要意义。随着技术的发展,我们可以通过实时获取天气数据来提供更准确可靠的天气预报。在本文中,我们将学习如何使用JavaScript和WebSocket技术,来构建一个高效的实时天气预报系统。本文将通过具体的代码示例来展示实现的过程。We

简易JavaScript教程:获取HTTP状态码的方法 简易JavaScript教程:获取HTTP状态码的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

javascript中如何使用insertBefore javascript中如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用于在DOM树中插入一个新的节点。这个方法需要两个参数:要插入的新节点和参考节点(即新节点将要被插入的位置的节点)。

JavaScript和WebSocket:打造高效的实时图像处理系统 JavaScript和WebSocket:打造高效的实时图像处理系统 Dec 17, 2023 am 08:41 AM

JavaScript是一种广泛应用于Web开发的编程语言,而WebSocket则是一种用于实时通信的网络协议。结合二者的强大功能,我们可以打造一个高效的实时图像处理系统。本文将介绍如何利用JavaScript和WebSocket来实现这个系统,并提供具体的代码示例。首先,我们需要明确实时图像处理系统的需求和目标。假设我们有一个摄像头设备,可以采集实时的图像数

See all articles