17

This question is similar to When using React Is it preferable to use fat arrow functions or bind functions in constructor? but a little bit different. You can bind a function to this in the constructor, or just apply arrow function in constructor. Note that I can only use ES6 syntax in my project.

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 = () => {};
 }
}

What's the pros and cons of these two ways? Thanks.

asked Apr 25, 2017 at 3:15

4 Answers 4

13

Option 1 is generally more preferable for certain reasons.

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

Prototype method is cleaner to extend. Child class can override or extend doSomething with

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

When instance property

this.doSomeThing = () => {};

or ES.next class field

doSomeThing = () => {}

are used instead, calling super.doSomething() is not possible, because the method wasn't defined on the prototype. Overriding it will result in assigning this.doSomeThing property twice, in parent and child constructors.

Prototype methods are also reachable for mixin techniques:

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

Prototype methods are more testable. They can be spied, stubbed or mocked prior to class instantiation:

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

This allows to avoid race conditions in some cases.

answered Apr 25, 2017 at 5:02
3
  • Thanks for your reply! This answer helps me a lot. Could you explain more about the 'race conditions in some cases'? Thanks. Commented Apr 25, 2017 at 6:39
  • For example if you want to mock doSomething or test that it was called, but it is called before you have a chance to spy/stub it on instance. This may happen if doSomething is called in constructor or somewhere else in code (when it is framework hook, etc). Commented Apr 25, 2017 at 12:47
  • Really thanks for your explanation. That helps me find a potential bug, thanks. Commented Apr 25, 2017 at 15:18
3

I think you may want like this. It is the same with your first situation. it will work in stage-2 with babel. (transform-class-properties : http://babeljs.io/docs/plugins/transform-class-properties/) (preset-stage-2: http://babeljs.io/docs/plugins/preset-stage-2/)

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

answered Apr 25, 2017 at 3:22
3
  • That's not valid es6. Commented Apr 25, 2017 at 3:24
  • 2
    Yes, but with bablerc, you can use plugins with stage-2, it will work. (transform-class-properties : babeljs.io/docs/plugins/transform-class-properties) (preset-stage-2: babeljs.io/docs/plugins/preset-stage-2) Commented Apr 25, 2017 at 3:35
  • thanks. But we can't apply any draft syntax in our project :( Commented Apr 25, 2017 at 3:46
3

Approach 1 is more readable for me and more idiomatic.

Besides, declaring methods inside a class instead of constructor, the methods can be shared.

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

In approach 2, you will declare all the methods every time you create a new instance:

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

Theoretically the approach 2 is slower, but the impact on performance should be negligible.

I'll simply go for approach 1, since it's used in the React documentation, also I never saw anyone use approach 2.


I just ran some samples to test the performance. In latest Chrome (Mac), declaring methods in constructor is about 90% slower than using bind in constructor.

answered Apr 25, 2017 at 3:25
7
  • 2
    your first code example does not hold when this.test = this.test.bind(this) is in the constructor like @ycavatars posted. f1.test === f2.test will evaluate to false. Commented Apr 25, 2017 at 3:33
  • of course not, bind() always returns a new method. but the declaration of the method itself can be shared Commented Apr 25, 2017 at 3:34
  • But @ycavatars is only asking about the case where bind is used. Commented Apr 25, 2017 at 3:37
  • With or without bind doesn't matter. bind simply wrap the method. It should be lighter and faster than declaring a new method Commented Apr 25, 2017 at 3:53
  • @CodinCat Can you share a performance test on jsperf? I wonder know why bind is faster than declaring methods. Thanks. Commented Apr 25, 2017 at 4:12
1

Check this out:

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

We can see babel transpiles

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

into

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

edit: I misread your post slightly, but the above is still true and interesting. @CodinCat points out the important thing: declaring a function inside the constructor means it takes time (albeit very little) to add that function to the object when it is created, and also probably takes memory because instances of that class don't share the same doSomeThing method.

edit2: binding (this) to the function actually causes the exact issues I listed above. In other words the two methods are almost exactly the same.

answered Apr 25, 2017 at 3:23

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.