2

I'm currently experimenting with ES6 classes and I've come across this issue that I don't fully understand. I want to make a class which is initialized by giving it a function. The class has a method that runs the function, but with any given context. I've attempted to do so with something like this:

class MyClass {
  constructor(action) {
    this.action = action;
  }
  run(context, n) {
    this.action.call(context, n);
  }
}

// instantiate my class with a function that uses 'this' to log a given number
let a = new MyClass((n) => {
  this.log(n);
})

// calls the run method of my class, giving console as the context and 1 as n.
a.run(console, 1);

I would expect this code to result in 1 being logged to the console. However, I'm instead getting a TypeError.

I assume I am misunderstanding something about how classes and context-binding work in ES6. Can anyone help me out?

Edit

Well this was a good lesson on the difference between arrow functions and function declarations. Thanks for the answers!

nficca
  • 23
  • 3
  • Related: [Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?](http://stackoverflow.com/q/34361379/218196) – Felix Kling Apr 05 '17 at 20:20

2 Answers2

0

The problem stems from how arrow functions work.

Arrow functions bind this to their lexical environment:

let obj = {
  a: 1,
  init() {
    this.log = () => console.log(this.a);
  }
};

obj.init();
obj.log();

// And the `this` value cannot be changed
obj.log.call({ a: 500 });

To fix your code, just define action with a regular function expression:

class MyClass {
  constructor(action) {
    this.action = action;
  }
  run(context, n) {
    this.action.call(context, n);
  }
}

let a = new MyClass(function(n) {
  this.log(n);
})

a.run(console, 1);
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
0

Your use of arrow functions is breaking things

let a = new MyClass((n) => {
  this.log(n);
});

is the same as

let _this = this;
let a = new MyClass(function(n) {
  _this.log(n);
});

because arrow functions look up the scope to their parent. You should use a normal function as

let a = new MyClass(function(n) {
  this.log(n);
});
loganfsmyth
  • 156,129
  • 30
  • 331
  • 251