我应该遵循 Visual Studio Code 建议在 javascript 中转换为命名函数吗?

use*_*530 0 javascript reactjs visual-studio-code

我在 ReactJS 应用程序中大量使用箭头函数样式(它们都使用带有钩子的函数样式)。

const handleKeyDown = (e) => {
    doStuff(e.keyCode);
}
Run Code Online (Sandbox Code Playgroud)

Visual Studio Code 一直在这里建议我使用一个命名函数,如:

function handleKeyDown(e) {
    doStuff(e.keyCode);
}
Run Code Online (Sandbox Code Playgroud)

这里的最佳做法是什么?我读过,箭头函数和命名函数在 javascript 中是等价的。这不是真的吗?在这里使用命名函数有什么好处吗?

ZER*_*ER0 6

有两个主要区别。

首先:

function handleKeyDown(e) {
    doStuff(e.keyCode);
}
Run Code Online (Sandbox Code Playgroud)

在这里,您使用的是函数声明(或函数语句);在箭头函数的情况下:

const handleKeyDown = (e) => {
    doStuff(e.keyCode);
}
Run Code Online (Sandbox Code Playgroud)

您正在使用函数表达式。事实上,它们被称为箭头函数表达式(因为没有“箭头函数声明”,它们的本质是一个表达式)。

所以更清楚地说,箭头函数版本更像是:

const handleKeyDown = function(e) {
  doStuff(e.keyCode);
}
Run Code Online (Sandbox Code Playgroud)

所以第一个区别是函数声明函数表达式,(因此语句和表达式之间的区别:Javascript:语句和表达式之间的区别?

对于与函数有关的内容,函数声明函数表达式没有的地方被提升。这意味着这样的代码:

handleKeyDown({keyCode: 13});

function handleKeyDown(e) {
    doStuff(e.keyCode);
}
Run Code Online (Sandbox Code Playgroud)

完全有效(并且正在运行),其中的代码如下:

handleKeyDown({keyCode: 13});

const handleKeyDown = (e) => {
    doStuff(e.keyCode);
}
Run Code Online (Sandbox Code Playgroud)

将引发异常,因为handleKeyDown尚未初始化。

函数表达式和函数声明之间的另一个区别是函数表达式是匿名的(未命名的)。这不再有效,因为 js 引擎现在能够确定与它们关联的名称:

const handleKeyDown = function(e) {
  doStuff(e.keyCode);
}
Run Code Online (Sandbox Code Playgroud)

但是,在这种情况下,箭头函数函数表达式之间的区别在于您可以覆盖它:

const bar = function baz() {};

console.log(bar.name) // baz
Run Code Online (Sandbox Code Playgroud)

然而,重要的是要注意,名称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
Run Code Online (Sandbox Code Playgroud)

当您想要一个递归函数而不用它污染外部作用域时,这会很有用。常见的例子是setTimeout

handleKeyDown({keyCode: 13});

function handleKeyDown(e) {
    doStuff(e.keyCode);
}
Run Code Online (Sandbox Code Playgroud)

RequestAnimationFrame

handleKeyDown({keyCode: 13});

const handleKeyDown = (e) => {
    doStuff(e.keyCode);
}
Run Code Online (Sandbox Code Playgroud)

也就是说,使用箭头函数表达式而不是函数(表达式或语句)的第二个主要区别是箭头函数本身的性质。MDN 有一个整洁的列表:

  1. 没有自己的 this 或 super 绑定,不应用作方法。
  2. 没有arguments(object) 或 new.target 关键字。
  3. 不适合call,applybind方法,一般依赖于建立范围。
  4. 不能用作构造函数。
  5. 不能使用yield,在其体内。

为什么他们不适合的原因callapply而且bind是因为他们使用的封闭范围的上下文对象定义时; 基本上他们没有this自己的。当您将它们用作事件处理程序时,这很明显:

const foo = () => {}
const bar = function() {}

console.log(foo.name) // "foo"
console.log(bar.name) // "bar"
Run Code Online (Sandbox Code Playgroud)

在哪里:

const bar = function baz() {};

console.log(bar.name) // baz
Run Code Online (Sandbox Code Playgroud)

总而言之,在定义可调用函数的每种方式之间肯定存在重叠区域的地方,每种方式都有自己的特征需要了解,以便正确使用它们,并避免可能出现的令人讨厌的错误。