Menu

JavaScript 箭头函数:=>、this 与适用场景

JavaScript 中箭头函数的工作方式:=> 语法、隐式返回、它们如何处理 this,以及什么时候该用它代替 function。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

一种更简短的函数写法

箭头函数是 JavaScript 中定义函数的一种更简洁的语法。它出现在 ES2015 中,如今已经是小型内联函数的默认写法,尤其是传给数组方法的回调、Promise 处理函数和事件监听器。

它的结构是:参数,然后是 =>,再然后是函数体。

和传统写法的结果完全一样:

const add = function (a, b) {
    return a + b;
};

少打几个字固然不错,但真正值得关注箭头函数的原因,是隐式返回以及它们对 this 的处理方式。下面就来讲这两点。

隐式返回

如果函数体只有一个表达式,你可以省略花括号和 return。表达式的值会被自动返回:

这正是箭头函数的用武之地:单行的转换读起来就像数学公式:

一旦需要多条语句,你就得回到花括号和显式的 return:

在花括号里忘写 return 是箭头函数最常见的错误。x => { x * 2 } 返回的是 undefined:花括号把函数体变成了一个代码块,里面的表达式结果被直接丢掉了。

参数的括号

只有一个参数时,括号可以省略:

没有参数,或者有两个及以上参数时,就必须写括号:

有些团队为了统一,喜欢始终加括号。两种风格都可以,选定一种并坚持下去就好。

返回对象字面量

这里有个坑。如果你想隐式返回一个对象,它的花括号看起来就像函数体:

这会打印 undefined。JavaScript 把 { name: name } 理解成一个包含带标签语句的代码块,而不是对象字面量。用括号把对象包起来,强制让它成为一个表达式:

在 { ... } 外面加上 () 就解决了。记住这一点:开始写箭头函数后的第一周内,你就会遇到它。

词法 this

箭头函数存在的真正原因并不是语法更短,而是它们没有自己的 this。它们从外层作用域继承 this。

为了理解这一点为什么重要,来看一个用作回调的普通函数:

在传给 setInterval 的 function () { ... } 内部,this 不是 counter。普通函数的 this 取决于它被调用的方式,而 setInterval 调用回调时,this 是 undefined(严格模式下)或全局对象。

箭头函数则会保留外层方法的 this:

在箭头函数内部,this 依然是 counter,因为箭头函数不会引入自己的 this。在有箭头函数之前,人们用 const self = this; 或 .bind(this) 来绕过这个问题。这些写法依然有效,但现在已经很少需要了。

箭头函数没有的东西

词法 this 规则只是一个更大规律的一部分:普通函数拥有的好几样东西,箭头函数都没有。

  • 没有自己的 this:从外层作用域继承。
  • 没有 arguments 对象:改用剩余参数(...args)。
  • 不能用 new:箭头函数不能用作构造函数。
  • 没有 prototype 属性:这是不能用 new 带来的结果。

...args 提供了和 arguments 一样的“接收任意数量参数”的能力,而且它还是一个真正的数组。new Greeter(...) 这次调用会抛出错误,因为箭头函数不是构造函数。

什么时候不该用箭头函数

箭头函数是回调的默认选择,但在少数场合它并不合适:

用箭头语法定义的对象方法,this 不会绑定到这个对象上,而是继承自对象字面量所在的位置(通常是模块或全局作用域)。定义方法时,请使用简写方法语法(greet() { ... })。

同样的道理也适用于类的原型方法、需要用 this 指向元素的事件处理方法,以及任何你打算用 new 调用的函数。这些地方应该用普通的 function。

简单的经验法则

  • 简短的回调,只有一个表达式? 用箭头函数。
  • 需要 this 保持绑定在外层作用域? 用箭头函数。
  • 在对象或类的原型上定义方法? 用普通函数(或简写方法)。
  • 编写构造函数? 用普通函数,更好的选择是 class。

在任何真实的 JavaScript 代码库中,你都会看到这两种写法。读上几周别人的代码,你就会知道哪种更合适,之后这种选择就会变成本能。

下一页:参数与默认值

箭头函数和普通函数共享同样的参数特性:默认值、剩余参数、解构参数等等。这就是下一页的内容,它适用于你目前见过的所有函数形式。

常见问题

JavaScript 中的箭头函数是什么?

箭头函数是一种更简短的函数写法,使用 => 语法。const add = (a, b) => a + b; 就是一个箭头函数,它接收两个参数并返回它们的和。除了语法更简洁,箭头函数不会绑定自己的 this、arguments 或 super,而是从外层作用域继承它们。

箭头函数和普通函数有什么区别?

用 function 声明的普通函数有自己的 this 和自己的 arguments 对象,还可以配合 new 用作构造函数。箭头函数这些都没有,它的 this 继承自定义它的地方。另外,箭头函数也不能像函数声明那样被提升。

什么时候应该用箭头函数?

简短的回调函数(arr.map(x => x * 2))适合用箭头函数;凡是希望 this 保持绑定在外层作用域的地方也适合,比如在类方法里把处理函数传给 setTimeout 或事件监听器时。对象上的方法、构造函数和独立的顶层函数,则用普通的 function。

Coddy 编程语言插图

和 Coddy 一起学编程

开始