【问题标题】:Should I follow Visual Studio Code suggesting a convert to named function in javascript?我应该遵循 Visual Studio Code 建议在 javascript 中转换为命名函数吗?
【发布时间】:2021-02-11 16:37:13
【问题描述】:

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

const handleKeyDown = (e) => {
    doStuff(e.keyCode);
}

Visual Studio Code 在这里不断提示,我使用了一个命名函数,例如:

function handleKeyDown(e) {
    doStuff(e.keyCode);
}

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

【问题讨论】:

    标签: javascript reactjs visual-studio-code


    【解决方案1】:

    取决于,在大多数情况下,它们执行相同的操作(箭头或命名函数)但它们有区别,箭头函数没有 this,因此它会在 closes 父范围内寻找他可以找到它,但命名函数有自己的上下文。

    老实说,我不知道为什么 VSCode 提议进行这种更改,但取决于您是使用类组件还是使用箭头函数的函数组件会更好。

    注意,我现在不使用类组件,但这个例子是为仍在使用它的人准备的。

    import React from 'react';
    
    class SomeComponent extends React.Component {
    
      constructor(props) {
        super(props);
        this._clickHandlerNamed = this._clickHandlerNamed.bind(this);
        this.myText = 'Some text';
      }
    
      _clickHandlerNamed(e) {
        console.log(this.myText);
      }
    
      _clickHandlerArrow = e => console.log(this.myText);
    
      render() {
        return(
          <div>
            <button onClick={this._clickHandlerNamed}>Named Function</button>
            <button onClick={this._clickHandlerArrow}>Arrow Function</button>
          </div>
        );
      }
    }
    

    正如你在构造函数中看到的那样,我们用一个新函数覆盖原来的this._clickHandlerNamed,而不是拥有自己的this上下文,而是使用父类的上下文,这允许访问this.myText SomeComponent 组件的属性。

    箭头函数没有上下文,因此将在树中查找最接近的this,因此应该能够访问this.myText 属性。

    【讨论】:

    • 是的,我的整个应用程序都可以正常运行。我还定义了类似const app = (props) =&gt; {} 的应用程序(VSC 建议进行相同的更改)。因此我不需要this。这就是为什么我通常使用箭头函数并且没有注意到与范围有关的任何障碍。
    • 继续这样做,因为在功能组件中没有必要使用它,永远不会
    【解决方案2】:

    有两个主要区别。

    第一个:

    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 有一个简洁的列表:

    1. 对 this 或 super 没有自己的绑定,不应用作方法。
    2. 没有arguments(对象)或new.target 关键字。
    3. 不适用于callapplybind 方法,它们通常依赖于建立作用域。
    4. 不能用作构造函数。
    5. 不能在其正文中使用yield

    它们不适合callapplybind的原因是因为它们在定义时使用了封闭范围的上下文对象;基本上他们自己没有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
    

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

    【讨论】:

    • 第二个@ZERO;恕我直言,他们的答案比公认的要好。
    猜你喜欢
    • 2016-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 2012-04-01
    • 1970-01-01
    相关资源
    最近更新 更多