First question on SO and I hope I’m not duplicating anything; I’ve looked at other questions and think mine is different enough to warrant asking.
Basically, is there a way to have the this
that’s in the method body of a method written using the shorthand notation to be either lexical or bound to a specific value?
The motivation for this comes from wanting to use the ES6 method shorthand when I was implementing the iterator protocol, in which the @@iterator
method, when called, returns an iterator object. That iterator object has to have a next()
method, which when called itself returns another object. It’s in this 2nd object that I want a reference to the original (in my case, Graph
) instance.
Note that in the below code snippet, which does not work as intended due to the this
binding, next()
is using the ES6 method definition shorthand.
class Graph {
constructor(initialNodes) {
this.data = [...initialNodes];
}
[Symbol.iterator]() {
let nextIndex = 0;
// `this` binding is fine here, as expected
return {
// look at that beautiful shorthand
next() {
return nextIndex < this.data.length
// `this` binding is not fine here
? { done: false, value: this.data[nextIndex++] }
: { done: true };
}
};
}
}
I’m aware of defining the function above the object return and then assigning that function as a property of the object being returned, but again I was wondering if a way with the method shorthand syntax was possible.
Defining next()
above the return object as a regular function then binding it in the object property assignment:
class Graph {
// constructor
[Symbol.iterator]() {
let nextIndex = 0;
// I know you can do this
const next = function() {
return nextIndex < this.data.length
? { done: false, value: this.data[nextIndex++] }
: { done: true };
};
return {
next: next.bind(this)
};
}
}
Defining next()
above the return object as an arrow function means no need for bind
, but still no method syntax shorthand:
class Graph {
// constructor
[Symbol.iterator]() {
let nextIndex = 0;
// I know you can also do this
const next = () => {
return nextIndex < this.data.length
? { done: false, value: this.data[nextIndex++] }
: { done: true };
};
return {
next
};
}
}
Icepickle brought up a good point in the comments that I could just use store the this
context and refer to that in the shorthand method body. I’m assuming this is the closest I can get?
class Graph {
// constructor
[Symbol.iterator]() {
let nextIndex = 0;
const self = this;
return {
next() {
return nextIndex < self.data.length
? { done: false, value: self.data[nextIndex++] }
: { done: true };
}
};
}
}
The ideal solution to your problem would be to use the proper tool for the job: a generator function. They too can be used with a shorthand syntax, and they will properly bind
this
.Generator functions return objects which conform to the iterator protocol, and can use
yield*
to delegate the output of the iterator to another iterable object (like an array).