什麼是箭頭函式 (Arrow Function)?跟一般的函式有什麼差別?
2022年10月27日
箭頭函式是在 ES6 後出現的一種函式表現方式,雖然也是函式的一種,但有部分的特性是跟一般函式有差異的,在面試中屬於高頻題,需要特別注意。
箭頭函式和一般函式差異
箭頭函式和一般函式的主要差異有四點,我們將在下方詳細說明:
- 箭頭函式語法不同、寫法也較簡潔
- 箭頭函式沒有自己的
this
、也無法直接修改this
的指向 - 箭頭函式沒有自己的
arguments
- 箭頭函式不能作為構造函式使用
語法更為簡潔
箭頭函式相比於一般函式,語法相當簡潔。除了少去 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、apply 和 bind 來綁定 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
總結
- 箭頭函式語法不同、寫法也較簡潔
- 箭頭函式沒有自己的
this
、也無法直接修改this
的指向 - 箭頭函式沒有自己的
arguments
- 箭頭函式不能作為構造函式使用