箭頭函數 Arrow function expression
箭頭函數(Arrow function)是 ES6 引入的更精簡的函式寫法。除了語法短,它跟一般 function 在 this、arguments、能否當建構式等行為上有本質差異 —— 這些差異才是面試重點。
語法
(param1, param2, …, paramN) => { statements }
//這種寫法表示一個帶有參數的箭頭函式,且有多行的函式內容。
(param1, param2, …, paramN) => expression
//相当于:(param1, param2, …, paramN) =>{ return expression; }
// 当只有一个参数时,圆括号是可选的:
(singleParam) => { statements }
singleParam => { statements }
// 没有参数的函数应该写成一对圆括号。
() => { statements }
隱式回傳(implicit return)
函式體是單一表達式且沒有大括號時,該表達式的值會被自動 return,不用寫 return 關鍵字。一旦加上 { },就變成一般函式體,沒寫 return 就回傳 undefined。
const add = (a, b) => a + b; // 隱式回傳,等同 return a + b
const add2 = (a, b) => { a + b; }; // ⚠️ 沒寫 return,回傳 undefined
回傳物件字面量要加括號因為 { 會被當成函式體的開頭,要回傳物件必須用 ( ) 把物件包起來,告訴解析器這是表達式不是 block。
//加括号的函数体返回对象字面量表达式:
params => ({foo: bar})
const makeUser = (name) => ({ name, role: 'user' });
makeUser('Bob'); // { name: 'Bob', role: 'user' }
//錯誤寫法:被當成 block,foo 被當 label,回傳 undefined
const wrong = () => { foo: bar };
剩餘參數、預設值、解構
//支持剩余参数和默认参数
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => {
statements }
//同样支持参数列表解构
let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
簡單範例
// 等同於 function add(a, b) { return a + b; }
const add = (a, b) => a + b;
console.log(add(1, 2)); // 3
// 等同於 function noop() { console.log('Hello World!') }
const noop = () => console.log('Hello World!');
noop(); // Hello World!
// 等同於 function square(x) { return x * x; }
const square = x => x * x;
console.log(square(5)); // 25
const add = (a, b) => {
const result = a + b;
console.log(`${a} + ${b} = ${result}`);
return result;
}
//我們可以這樣呼叫 add 函數:
add(3, 4); // 輸出 "3 + 4 = 7"
const printPerson = (name, age) => {
console.log(`My name is ${name} and I'm ${age} years old.`);
}
printPerson("John", 30); // 輸出 "My name is John and I'm 30 years old."
跟一般 function 的差異(面試重點)
| 特性 | 一般 function | 箭頭函數 |
|---|---|---|
this 綁定 | 動態(由呼叫方式決定) | 詞法綁定(lexical,定義時就固定) |
arguments | 有自己的 | 沒有,沿用外層 |
當建構式 new | 可以 | ❌ 丟 TypeError |
prototype 屬性 | 有 | ❌ 沒有 |
yield / generator | 可以 | ❌ 不能當 generator |
call/apply/bind 改 this | 有效 | 對 this 無效(只能傳參數) |
1. this 詞法綁定 ⭐ 最常考
一般 function 的 this 取決於怎麼被呼叫(誰在點它、有沒有 new、有沒有 call/apply)。箭頭函數沒有自己的 this,它的 this 在定義當下就決定了 —— 直接取「外層作用域」的 this,而且事後無法改變。
const obj = {
count: 0,
// 一般 function:setInterval 呼叫時 this 是 undefined / window
startWrong() {
setInterval(function () {
this.count++; // ❌ this 不是 obj
console.log(this.count); // NaN
}, 1000);
},
// 箭頭函數:this 繼承自 startRight 的 this,也就是 obj
startRight() {
setInterval(() => {
this.count++; // ✅ this 是 obj
console.log(this.count); // 1, 2, 3...
}, 1000);
},
};
這也是箭頭函數最大的賣點:取代以前 const self = this; 或 .bind(this) 的 workaround。
// 舊寫法
function Timer() {
var self = this;
self.seconds = 0;
setInterval(function () { self.seconds++; }, 1000);
}
// 箭頭函數版本,不需要 self
function Timer() {
this.seconds = 0;
setInterval(() => { this.seconds++; }, 1000);
}
call / apply / bind 改不了箭頭函數的 this因為箭頭函數根本沒有自己的 this,fn.call(otherObj) 只能傳參數,this 仍是定義時的外層 this。
2. 沒有自己的 arguments
箭頭函數不綁定 arguments,引用 arguments 會抓到外層函式的。要拿到全部參數請用 rest 參數 ...args。
function outer() {
const inner = () => arguments[0]; // 抓的是 outer 的 arguments
return inner();
}
outer('a', 'b'); // 'a'
// 正確:用 rest 參數
const sum = (...args) => args.reduce((a, b) => a + b, 0);
sum(1, 2, 3); // 6
3. 不能當建構式(no new)
箭頭函數沒有 Construct 內部方法,也沒有 prototype,所以不能 new。
const Person = (name) => { this.name = name; };
const p = new Person('Bob'); // ❌ TypeError: Person is not a constructor
console.log(Person.prototype); // undefined
何時該用 / 何時不該用
✅ 適合用箭頭函數:
- callback / 高階函式參數(
map、filter、reduce、forEach) - 需要保留外層
this的情境(setTimeout、Promise then、event handler 內部、React class 元件的 method) - 一行的小工具函式(隱式回傳很乾淨)
❌ 不該用箭頭函數:
物件方法(method)
物件 method 用箭頭函數會讓 this 指向外層(通常是 window / module),不是物件本身。
const counter = {
count: 0,
// ❌ 錯:this 不是 counter
incWrong: () => { this.count++; },
// ✅ 對:用 method 簡寫或一般 function
inc() { this.count++; },
};
counter.incWrong(); // this.count 不會動到 counter.count
DOM 事件 handler 想用 this 指元素時
一般 function 當 event handler 時,this 是觸發事件的 DOM 元素;箭頭函數的 this 則是外層,拿不到元素。
// ❌ this 是外層 (window),不是被點的 button
button.addEventListener('click', () => {
this.classList.toggle('active'); // this.classList undefined
});
// ✅ 一般 function,this 是 button
button.addEventListener('click', function () {
this.classList.toggle('active');
});
// 或:箭頭函數搭配 event.currentTarget(不依賴 this)
button.addEventListener('click', (e) => {
e.currentTarget.classList.toggle('active');
});
需要 prototype / generator / 動態 this 的場景
建構式、原型方法、generator 函式都不能用箭頭函數。
一句話總結「需要自己的 this、arguments、能被 new」→ 用一般 function;「想沿用外層 this、寫得短」→ 用箭頭函數。