What a great question!
So, this
definitely looses its reference in this case, but if you really want to, there are at least three ways to work around this, depending on your situation. These examples are based solely on Ori Drori`s and Ilshidur’s answers to a similar question over on StackOverflow, so I definitely encourage you to go read their full answers, with a different base example, and please give his answer a thumbs up while you’re there!
Anyway, here are the ways they suggest, as applied to your example. (I wish we could have live code snippets here in discourse
, oh well, you’ll just have to move them to your repl of choice.)
Approach 1: Auto-bind with a getter
const scoreTracker = {
score: 0,
_incrementScore(){
return this.score += 1;
},
get incrementScore(){
if(!this._incrementScore.name.startsWith('bound ')) {
this._incrementScore = this._incrementScore.bind(this);
}
return this._incrementScore;
},
resetScore(){
return this.score = 0;
}
}
const { incrementScore } = scoreTracker;
console.log(incrementScore);
console.log(incrementScore());
console.log(incrementScore());
console.log(incrementScore());
Approach 2: Auto-bind with a Proxy
const handler = {
get: function(target, prop, receiver) {
// if method, and not bound, bind the method
if (
typeof target[prop] === 'function'
&& !target[prop].name.startsWith('bound ')
) {
target[prop] = target[prop].bind(target);
}
return target[prop];
}
};
const scoreTracker = new Proxy({
score:0,
incrementScore(){
return this.score += 1;
},
resetScore(){
return this.score = 0;
}
}, handler);
const {incrementScore} = scoreTracker;
console.log(incrementScore);
console.log(incrementScore());
console.log(incrementScore());
console.log(incrementScore());
Approach 3: Class binding
class ScoreTracker {
// field declarations not currently supported, but at stage 3
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Field_declarations
// score = 0;
constructor() {
this.score = 0;
this.incrementScore = this.incrementScore.bind(this);
}
incrementScore(){
return this.score += 1;
}
resetScore(){
return this.score = 0;
}
}
const { incrementScore } = new ScoreTracker();
console.log(incrementScore);
console.log(incrementScore());
console.log(incrementScore());
console.log(incrementScore());