Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a good way to automatically bind JS class methods?

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));
like image 761
Dominic P Avatar asked Jun 08 '19 04:06

Dominic P


People also ask

Will ES6 classes bind the instance automatically?

[React Component Class] Methods follow the same semantics as regular ES6 classes, meaning that they don't automatically bind this to the instance.

What does bind () method of?

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

How can you avoid the need for binding class methods to a class instance?

Binding this allows it to access the state and setstate inside the class. To avoid the need for binding we have something introduced in ES6 as arrow functions. Using the arrow function to call this. setState will lead to avoid the use of bind.

Why do we use .bind JS?

bind is a method on the prototype of all functions in JavaScript. It allows you to create a new function from an existing function, change the new function's this context, and provide any arguments you want the new function to be called with.


1 Answers

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)); 
like image 102
lvnam96 Avatar answered Oct 12 '22 11:10

lvnam96