35

I get tired of writing code like this:

class Something {

    constructor() {

        this.method = this.method.bind(this);
        this.anotherOne = this.anotherOne.bind(this);
        // ...
    }
}

It's time consuming and it's easy to forget to bind a method. I aware of the class fields proposal, but it's still Stage 3 and seems to come with some issues.

My current solution (based on this answer) looks like this:

class Something {

    constructor() {

        // Get all defined class methods
        const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(this));

        // Bind all methods
        methods
            .filter(method => (method !== 'constructor'))
            .forEach((method) => { this[method] = this[method].bind(this); });
    }
}

This seems to work, but I'm wondering if there is a better way, or if this method has issues that I'm not aware of.

Update: Why Do This?

The problem I have run into is that if I don't bind my class functions in the constructor, I have to remember to call them "properly" later. For example:

const classInstance = new Something();

// This fails for a non-obvious reason
someAction()
    .then(classInstance.method);

// This works of course but looks like we created a useless function if you don't know better
someAction()
    .then(result => classInstance.method(result));
Dominic P
  • 2,284
  • 2
  • 27
  • 46
  • I'd extract the binding out into a separate function, rather than being in the constructor – CertainPerformance Jun 08 '19 at 04:55
  • 1
    One option, considering you only need to bind methods that are called in a different context (usually an event handler), is to use arrow functions to call these methods without changing the context. – Randy Casburn Jun 08 '19 at 04:55
  • Is there a reason you are using ES5 instead of fat arrow syntax? – Michael Paccione Jun 08 '19 at 04:57
  • 3
    Why do you feel like you have to do this at all? – user229044 Jun 08 '19 at 05:19
  • Thanks for the feedback. CertainPerformance, what is the advantage of putting it in a separate function? Just a cleaner constructor? Randy, Michael, and meagar, the problem I have run into is that if I don't bind in the constructor, I have to remember to call class functions the "right" way later. – Dominic P Jun 08 '19 at 21:11
  • 4
    What about `this.self = this` approach? That's not discussed here... – Ryan Nov 11 '21 at 20:13
  • I'm not familiar with that approach @Ryan could you share a bit about it (possibly in an answer)? – Dominic P Nov 12 '21 at 00:48
  • 1
    @DominicP - Just referring to the old idiom discussed here: https://stackoverflow.com/questions/962033/what-underlies-this-javascript-idiom-var-self-this. Seems like this approach is no longer necessary or recommended so, nevermind :). – Ryan Nov 15 '21 at 18:55
  • Ok, yeah, I see what you mean. Thanks for clarifying. – Dominic P Nov 15 '21 at 22:08

5 Answers5

34

Use fat arrow function in ES6 (generally called as arrow function)

anotherOne = ()=> {
...
}

Call like this onClick={this.anotherOne}; no need to bind in constuctor

From the ECMA spec

Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.

kiranvj
  • 32,342
  • 7
  • 71
  • 76
  • 4
    I don't see how this bind methods of an object to its instance at all. Doesn't seem to answer the question asked. – jfriend00 Jun 08 '19 at 05:16
  • 2
    OP already mentioned this, and said that he doesn't like the issues that come with it. @jfriend00 ? This is class field syntax, it means that `this` inside the function will be bound to the instance without an extra `.bind`, right? Probably not what OP was looking for given that he explicitly mentioned it as a discarded possibility, though – CertainPerformance Jun 08 '19 at 05:19
  • @CertainPerformance - Well, the answer does not show enough context of the definition to know that's what they were doing. Certainly wasn't obvious to me. – jfriend00 Jun 08 '19 at 05:23
  • 1
    You seem to be missing to mention that this relies on the *public class fields* feature. – Felix Kling Jun 08 '19 at 09:51
17

It seems a bit late to answer this question but there is no accepted answer so I will try my best for people come here after me.

To automatically bind this for all methods, you can use "arrow" function:

class Something {
  constructor() {
    // Don't need to bind `this`
  }

  doSomething = () => {
    console.log(this); // `this` will be pointed to the instance
  }
}

const s = new Something();
s.doSomething(); // => `this` is pointed to `s`

Note: just make sure the classes extending this class Something will not use doSomething method in its constructor (eg: super.doSomething()), otherwise you will get an error.

To answer the updated question: if you don't manually bind this using .call() or .apply(), the value of this depends on the way that method is called

For example:

class Something {
  constructor() {
    // didn't bind `this` here
  }

  doSomething() {
    console.log(this);
  }
}

const s = new Something();
const funcA = s.doSomething;
const object = {
  funcB: s.doSomething,
};

// these ways of calling `.doSomething()` result in different values of `this`:
funcA(); // => `this` is pointed to the global variable (`window` in browser environment)
window.funcA(); // => same as `funcA()`
s.doSomething(); // => `this` is pointed to `s`
object.funcB(); // =? `this` is pointed to `object`

Beside that, the implementation of .then() method would be similar like this:

class Promise {
  // ...
  then(callback) {
    // code...
    callback(); // notice how the `callback` is called - not as a method of an object
    // code...
  }
}

With your code example, the way you pass the callback into .then() method will affect the value of this inside the callback:

const classInstance = new Something();

// `this` inside `classInstance.method` is pointed to `this` inside the
// `.then` method, not the `classInstance`, as `classInstance.method()`
// will be called as `callback()`
someAction()
    .then(classInstance.method);

// `this` inside `classInstance.method` is pointed to `classInstance`,
// as the way the anonymous "arrow" function is called does not affect the way
// `classInstance.method` is called, so `this`'s value is controlled by the way
// you call it inside the callback (anonymous "arrow" function) of `.then()`
// method.
someAction()
    .then(result => classInstance.method(result)); 
nobody
  • 329
  • 2
  • 8
8

You can also use auto-bind like this

From usage example:

const autoBind = require('auto-bind');

class Unicorn {
    constructor(name) {
        this.name = name;
        autoBind(this);
    }

    message() {
        return `${this.name} is awesome!`;
    }
}

const unicorn = new Unicorn('Rainbow');

// Grab the method off the class instance
const message = unicorn.message;

// Still bound to the class instance
message();
//=> 'Rainbow is awesome!'

// Without `autoBind(this)`, the above would have resulted in
message();
//=> Error: Cannot read property 'name' of undefined
alexlz
  • 618
  • 1
  • 10
  • 24
4

You can use an ES6 arrow function:

method = () => {
    //Do stuff
}

As stated in the docs:

An arrow function expression is a syntactically compact alternative to a regular function expression, although without its own bindings to the this, arguments, super, or new.target keywords.

Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
2

Class fields can be used to create functions automatically bound to the current instance.

class X {
  fn = () => console.log(this.constructor.name)
}
const x = new X;
x.fn(); // regular call
const fn = x.fn;
fn(); // this is preserved
const fn2 = x.fn.bind(null);
fn2(); // cannot rebind this
Unmitigated
  • 76,500
  • 11
  • 62
  • 80