我可以在反应组件的构造函数中使用箭头函数吗?

Posted

技术标签:

【中文标题】我可以在反应组件的构造函数中使用箭头函数吗?【英文标题】: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 = () => ;
  

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

【问题讨论】:

【参考方案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 = () => 

【讨论】:

这不是有效的 es6。 是的,但是使用 bablerc,您可以使用带有 stage-2 的插件,它会起作用。 (transform-class-properties : babeljs.io/docs/plugins/transform-class-properties) (preset-stage-2: babeljs.io/docs/plugins/preset-stage-2) 谢谢。但是我们不能在我们的项目中应用任何语法草案:(【参考方案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)到函数实际上会导致我上面列出的确切问题。换句话说,这两种方法几乎完全相同。

【讨论】:

以上是关于我可以在反应组件的构造函数中使用箭头函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用构造函数与 state = 在反应组件中声明状态有啥区别?

同一个MFC工程中的两个普通类,为啥一个构造函数打点有反应,一个构造函数打点没反应?是因为设置问题吗

使用 Angular 元素调用组件构造函数两次

箭头函数“this”绑定在 React 组件中不起作用 [重复]

如何在反应组件中访问 url 参数

[react] react中除了在构造函数中绑定this,还有别的方式吗?