【问题标题】:Can I use arrow function in constructor of a react component?我可以在反应组件的构造函数中使用箭头函数吗?
【发布时间】:2017-09-21 21:29:00
【问题描述】:

这个问题与When using React Is it preferable to use fat arrow functions or bind functions in constructor? 类似,但有点不同。您可以在构造函数中将函数绑定到this,或者只在构造函数中应用箭头函数。请注意,我的项目中只能使用 ES6 语法。

1.

class Test extends React.Component{
  constructor(props) {
    super(props);

    this.doSomeThing = this.doSomeThing.bind(this);
  }

  doSomething() {}
}

2.

class Test extends React.Component{
  constructor(props) {
    super(props);

    this.doSomeThing = () => {};
  }
}

这两种方式的优缺点是什么?谢谢。

【问题讨论】:

    标签: javascript reactjs constructor ecmascript-6 arrow-functions


    【解决方案1】:

    出于某些原因,选项 1 通常更可取。

    class Test extends React.Component{
      constructor(props) {
        super(props);
    
        this.doSomeThing = this.doSomeThing.bind(this);
      }
    
      doSomething() {}
    }
    

    原型方法更易于扩展。子类可以覆盖或扩展doSomething

    doSomething() {
      super.doSomething();
      ...
    }
    

    当实例属性

    this.doSomeThing = () => {};
    

    或 ES.next 类字段

    doSomeThing = () => {}
    

    改为使用,调用super.doSomething() 是不可能的,因为该方法没有在原型上定义。覆盖它将导致在父构造函数和子构造函数中分配this.doSomeThing 属性两次。

    混合技术也可以使用原型方法:

    class Foo extends Bar {...}
    Foo.prototype.doSomething = Test.prototype.doSomething;
    

    原型方法更具可测试性。它们可以在类实例化之前被监视、存根或模拟:

    spyOn(Foo.prototype, 'doSomething').and.callThrough();
    

    这允许在某些情况下避免竞争条件。

    【讨论】:

    • 感谢您的回复!这个答案对我帮助很大。您能否详细解释一下“某些情况下的竞争条件”?谢谢。
    • 例如,如果您想模拟 doSomething 或测试它是否被调用,但在您有机会在实例上监视/存根之前调用它。如果在构造函数或代码中的其他地方(当它是框架挂钩等)调用 doSomething 时,可能会发生这种情况。
    • 非常感谢您的解释。这有助于我找到潜在的错误,谢谢。
    【解决方案2】:

    方法 1 对我来说更易读,也更惯用。

    此外,在类中声明方法而不是构造函数,方法可以共享。

    class Foo {
      test() {}
    }
    
    const f1 = new Foo()
    const f2 = new Foo()
    f1.test === f2.test // true
    

    在方法 2 中,您将在每次创建新实例时声明所有方法:

    class Foo {
      constructor() {
        this.test = () => {}
      }
    }
    
    const f1 = new Foo()
    const f2 = new Foo()
    // the method is not shareable
    f1.test === f2.test // false
    

    理论上方法 2 速度较慢,但​​对性能的影响应该可以忽略不计。

    我会简单地选择方法 1,因为它在 React documentation 中使用过,而且我从未见过有人使用方法 2。


    我刚刚运行了一些样本来测试性能。在最新的 Chrome (Mac) 中,在构造函数中声明方法比在构造函数中使用 bind 慢约 90%。

    【讨论】:

    • this.test = this.test.bind(this) 在像@ycavatars 发布的构造函数中时,您的第一个代码示例不成立。 f1.test === f2.test 将评估为假。
    • 当然不是,bind() 总是返回一个新方法。但是方法本身的声明是可以共享的
    • 但是@ycavatars 只是询问使用绑定的情况。
    • 有或没有bind 都没有关系。 bind 只是简单地包装方法。它应该比声明一个新方法更轻更快
    • @CodinCat 你能分享一个关于jsperf的性能测试吗?我想知道为什么 bind 比声明方法更快。谢谢。
    【解决方案3】:

    我想你可能想要这样。你的第一种情况也是这样。 它将在第 2 阶段与 babel 一起工作。 (转换类属性:http://babeljs.io/docs/plugins/transform-class-properties/) (预设阶段 2:http://babeljs.io/docs/plugins/preset-stage-2/

    class Test extends React.Component{
      constructor(props) {
        super(props);
      }
      doSomeThing = () => {}
    }

    【讨论】:

    【解决方案4】:

    看看这个:

    https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-2&targets=&browsers=&builtIns=false&debug=false&code=class%20Dog%20%7B%0A%20%20constructor()%20%7B%0A%20%20%20%20%0A%20%20%20%20this.cat%20%3D%20_%3D%3E%20%7B%0A%20%20%20%20%20%20this%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D

    我们可以看到 babel 转译

    this.doSomeThing = () => { this };
    

    进入

    var _this = this;
    this.doSomething = function() { _this }
    

    编辑:我稍微误读了您的帖子,但以上内容仍然真实且有趣。 @CodinCat 指出了重要的一点:在构造函数中声明一个函数意味着在创建对象时将该函数添加到对象中需要时间(尽管很少),并且还可能占用内存,因为该类的实例不共享相同的 doSomeThing 方法。

    edit2:绑定(this)到函数实际上会导致我上面列出的确切问题。换句话说,这两种方法几乎完全相同。

    【讨论】:

      猜你喜欢
      • 2021-09-26
      • 2018-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-02
      • 2010-12-19
      • 2017-01-06
      相关资源
      最近更新 更多