Robodude Robodude - 1 month ago 4
Javascript Question

Javascript Class loses reference to 'this' (using babel)

class UrlProvider {
constructor(root) {
this.root = root;
}

getUrl() {
return this.root + "/api/Situations";
}
}


class Repository {
constructor(urlProvider) {
this.urlProvider = urlProvider;
}

getAsync() {
var self = this;
return httpGetAsync(self.urlProvider.getUrl()).then(function(d) {
return d.map(x => new Situation(x));
});
}
}



class PromiseCacher {
constructor(cache, promise) {
var self = this;
self.cache = cache;
self.promise = promise;
}
runAsync() {
var self = this;

return self.promise().then(function (d) {
self.cache.set(d);
return d;
});
}
}

var urlProvider = new UrlProvider(appsettings.url);
var repository = new Repository(urlProvider);
var cache = new Cache();

var promiseCacher = new PromiseCacher(cache, repository.getAsync);

promiseCacher.runAsync()


When debugging the above code, chrome will crash inside the getAsync function of the repository because self.urlProvider is undefined.
Inside the repository getAsync function 'this' is referring to the instance of PromiseCacher which is what actually calls it.

What's going on?

Re-writing

var promiseCacher = new PromiseCacher(cache, ()=> repository.getAsync());


makes it work as I would expect.

Answer

That's because first of all repository.getAsync is not a promise. Instead it is a function. By storing the reference of repository.getAsync to a different object property you "alter" its this value. Take a look at the following example:

var obj = {
    a: 42,
    func: function(){
        return this.a;
    }
};

obj.func();  // 42

var b = obj.func;
b();         // undefined

The example is comparable to your code:

class Repository{
    // urlProvider = ...
    getAsync (){ /* ... */ }
}

var repo = new Repository(/* ... */).getAsync;
repo.getAsync();  // works

var cacher = new PromiseCacher(/* ... */);
cacher.promise = repo.getAsync;
cacher.promise();  // does not work
Comments