什么是箭头函数

85 阅读4分钟

箭头函数是在 ES6 后出现的一种函数表现方式,虽然也是函数的一种,但有部分的特性是跟一般函数有差异的,在面试中属于高频题,需要特别注意。

箭头函数和一般函数的区别

箭头函数和一般函数的主要差异有四点,我们将在下方详细说明:

  1. 箭头函数语法不同、写法也较简洁
  2. 箭头函数没有自己的 this、也无法直接修改 this 的指向
  3. 箭头函数没有自己的 arguments
  4. 箭头函数不能作为构造函数使用

语法更为简洁

箭头函数相比于一般函数,语法相当简洁。除了少去 function 关键字,如果只有一个参数,箭头函数可以省略括号;只有一行代码,就是直接简单返回一个变量或简单的表达式,可以省略大括号和 return。例子如下:

// ES5 一般函数
let addOne = function (n) {
  return n + 1;
};
// ES6 箭头函数,参数只有一个时,参数的括号可以省略
let addOne = (n) => {
  return n + 1;
};
// ES6 箭头函数,只有一行时,省略大括号和 return
let addOne = (n) => n + 1;

this 值与一般函数不同

箭头函数没有自己的 this 值,箭头函数的 this 值是在一开始定义时就决定,永远会是最接近自己的外层的普通函数中的 this 值。此外,箭头函数也不适合使用 call、 applybind 来绑定 this 值,绑定值会无效。一般函数的 this 值,则是基于函数如何被调用来决定的。

一般函数中 this 可以被绑定,以下为代码绑定示例

const obj = {
  num: 100,
};

window.num = 2020;

const add = function (a, b, c) {
  return this.num + a + b + c;
};

// 绑定 this 值为 obj,obj 的 num 为 100,所以 resultCall 是 106
const resultCall = add.call(obj, 1, 2, 3);
console.log(resultCall); // 106

箭头函数中 this 绑定会无效,以下为代码绑定示例

const obj = {
  num: 100,
};

window.num = 2020;

const add = (a, b, c) => this.num + a + b + c;

// 绑定 this 无效,add 函数的 this 会是 window
// 所以 num 会是 2020,resultCall 则是 2026
console.log(add.call(obj, 1, 2, 3)); // 2026

利用 箭头函数 没有自己的 this 值的特性,很适合用在 setTimeout()EventTarget.prototype.addEventListener() 等方法当中,因为它可以自动绑定在适合的范围中。可以看到下方 setTimeout 当中,用一般函数与用箭头函数的 this 区别:

// 一般函数版本,this 值在这状况是 NaN
const obj = {
  count: 10,
  doSomethingLater() {
    setTimeout(function () {
      // 此 function 为一般函数,因此 this 指向 window
      this.count++;
      console.log(this.count); // NaN (因为在 windonw 中没有 count)
    }, 300);
  },
};
obj.doSomethingLater();

// 箭头函数版本
const obj = {
  count: 10,
  doSomethingLater() {
    // 此 function 为箭头函数,因此 this 会依据最接近的父层一般函数的 this 值,这里为 obj
    setTimeout(() => {
      this.count++;
      console.log(this.count); // 11 (obj 的 count 原本是 10,10++ 会是 11)
    }, 300);
  },
};
obj.doSomethingLater();

没有自己的 arguments

不像一般函数,箭头函数没有 arguments 对象,但好处是,箭头函数可以获取最近的非箭头函数的 arguments 对象,如下示例

箭头函数中 arguments 代码示例

// 箭头函数没有自己的 arguments,因此会往父层寻找
// 这边的父层是全局环境,因此找到全局环境中的 arguments 变量
// 在全局环境 arguments[0] 为 1
const arguments = [1, 2, 3];
const arr = () => arguments[0];
arr(); // 1

// 一般函数有 arguments 对象,就是传入的参数,在这边的 arguments 是 [3]
// 所以 arguments[0] 也会是 3
// f() 则会是 3 + 3
function foo(n) {
  const f = () => arguments[0] + n;
  return f();
}
foo(3); // 3 + 3 = 6

如果需要使用到箭头函数的所有参数,可以用以下 剩余参数 (rest parameter) 的写法得到

let nums = (...nums) => {
  console.log(nums);
};
nums(1, 2, 3, 4, 5); //[1,2,3,4,5]

不能作为构造函数使用

箭头函数不能作为构造函数使用,换言之不能用 new 关键字调用,会报错

const arrowFun = () => {};
new arrowFun(); // error: arrowFun is not a constructor

总结

  1. 箭头函数语法不同、写法也较简洁
  2. 箭头函数没有自己的 this、也无法直接修改 this 的指向
  3. 箭头函数没有自己的 arguments
  4. 箭头函数不能作为构造函数使用