有两个主要区别。
第一个:
function handleKeyDown(e) {
doStuff(e.keyCode);
}
你在这里使用function declaration(或函数语句);在箭头函数的情况下:
const handleKeyDown = (e) => {
doStuff(e.keyCode);
}
您使用的是function expression。实际上,它们被称为箭头函数表达式(由于没有“箭头函数声明”,它们的本质就是一个表达式)。
所以为了更清楚,箭头函数版本更像是:
const handleKeyDown = function(e) {
doStuff(e.keyCode);
}
所以第一个区别是函数声明 vs 函数表达式,(因此语句和表达式之间的区别:Javascript: difference between a statement and an expression?)
关于函数,函数声明是hoisted,而函数表达式不是。这意味着这样的代码:
handleKeyDown({keyCode: 13});
function handleKeyDown(e) {
doStuff(e.keyCode);
}
完全有效(并且正在运行),其中的代码如下:
handleKeyDown({keyCode: 13});
const handleKeyDown = (e) => {
doStuff(e.keyCode);
}
将引发异常,因为 handleKeyDown 尚未初始化。
函数表达式和函数声明之间的另一个区别是函数表达式是匿名的(未命名)。这不再有效,因为 js 引擎现在能够确定与它们关联的名称:
const foo = () => {}
const bar = function() {}
console.log(foo.name) // "foo"
console.log(bar.name) // "bar"
然而,箭头函数和函数表达式之间的区别,在这种情况下,你可以重写它:
const bar = function baz() {};
console.log(bar.name) // baz
但是,需要注意的是,名称 baz 的作用域是函数的主体块。这意味着在外面不可用:
const bar = function baz() {
console.log("my name is:", baz.name)
}
console.log(bar.name) // "baz"
bar() // "my name is: baz"
baz() // ReferenceError: bar is not defined
当您想要一个递归函数而不用它污染外部范围时,这可能很有用。常见的例子有setTimeout:
setTimeout(function foo() {
doStuff();
let time = calcNewTime();
setTimeout(foo, time)
}, 1000);
或RequestAnimationFrame:
requestAnimationFrame(function render() {
updateCoordinates();
renderGameScene();
requestAnimationFrame(render);
});
也就是说,使用箭头函数表达式而不是函数(表达式或语句)的第二个主要区别是arrow functions 本身的性质。 MDN 有一个简洁的列表:
- 对 this 或 super 没有自己的绑定,不应用作方法。
- 没有
arguments(对象)或new.target 关键字。
- 不适用于
call、apply 和bind 方法,它们通常依赖于建立作用域。
- 不能用作构造函数。
- 不能在其正文中使用
yield。
它们不适合call、apply和bind的原因是因为它们在定义时使用了封闭范围的上下文对象;基本上他们自己没有this。当您将它们用作事件处理程序时,这一点很明显:
const obj = {
handleClick() {
console.log("I clicked ", this)
}
}
button.addEventListener("click", obj.handleClick);
button.click(); // "HTMLButtonElement"
地点:
const obj = {
handleClick: () => {
console.log("I clicked ", this)
}
}
button.addEventListener("click", obj.handleClick);
button.click(); // "Window", assuming you execute this code in a browser
总而言之,定义可调用函数的每种方法之间肯定存在重叠区域,每种方法都有其自己的特征,以便正确使用它们,并避免可能出现的讨厌的错误。