什么是箭头函式 (Arrow Function)?跟一般的函式有什么差别?

2022年10月27日

💎 加入 E+ 成長計畫 與超過 500+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

箭头函式是在 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 值。

此外,箭头函式也不适合使用 callapplybind 来绑定 this 值,绑定值会无效。一般函式的 this 值,则是基于函式如何被调用来决定,详细可参考 《请解释 JavaScript 中 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. 箭头函式不能作为构造函式使用
🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們