什么是箭头函式 (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
- 箭头函式不能作为构造函式使用