AmmarCSE AmmarCSE - 6 months ago 37
Javascript Question

this binding not working as expected in forEach arrow function

I have a class in which I bind some functions in the constructor. This works fine and as expected

class Row {
constructor(props) {
super(props)
this.onEditRowClick = this.onEditRowClick.bind(this)
this.onCommitRowClick = this.onCommitRowClick.bind(this)
this.onDeleteRowClick = this.onDeleteRowClick.bind(this)
this.onCellChange = this.onCellChange.bind(this)
}
...
}


however, if I change to

class Row {
constructor(props) {
super(props)

let handlers = [this.onEditRowClick, this.onCommitRowClick, this.onCellChange, this.onDeleteRowClick]
handlers.forEach(handler => {handler = handler.bind(this)})
}
...
}


it is clearly not working as I get exceptions indicating that
this
in my function invocations is
null
.

I thought arrow functions implemented a lexical
this
binding?

Also, if I do this

class Row {
constructor(props) {
super(props)

[this.onEditRowClick, this.onCommitRowClick, this.onCellChange, this.onDeleteRowClick].forEach(handler => {handler = handler.bind(this)})
}
}


I get

Uncaught TypeError: Cannot read property 'forEach' of undefined


while this is totally fine

[1,2,3].forEach(function(item){console.log(item)})


Maybe Im missing something very obvious and it's time for me to go to bed?

Answer

Function.prototype.bind() creates new function from the existing one which is bound to the passed context. Therefore you reassign properties in your first working example:

this.onEditRowClick = this.onEditRowClick.bind(this);

However in your latter example you skipped the reassign phase. To solve this you can iterate over method names, bind it to the this instance and reassign:

class Row {
  constructor(props) {
    super(props);

    let handlers = [
      'onEditRowClick',
      'onCommitRowClick',
      'onCellChange',
      'onDeleteRowClick'
    ];

    handlers.forEach(handler => {
        this[handler] = this[handler].bind(this);
    });
  }
  ...
}