Reputation: 851
I'm building a visualization page (with dc.js
) for which I decided to make the jump and gather it all into a single namespace. Coming from Python's simplicity, crashing against JavaScript's scope madness has been tough enough, so please bear with me.
I have a general JS structure as follows:
var NamespaceClass = function() {
this.var0 = "something";
this.var1 = dc.SomeChartClass("#some-css-selector");
this.setup = function(error, config, dataset) {
console.log("Inside setup:", this);
this.var2 = this.process_data(dataset);
// Do some more stuff...
}
this.process_data = function(data) {
var whatever;
//Do stuff with "data"...
return whatever;
}
this.start = function() {
console.log("Inside start:", this);
var q;
q = queue().defer(d3.json, "config.json")
.defer(d3.csv, "data.csv");
q.await(this.setup);
}
}
var MyNamespace = new NamespaceClass();
MyNamespace.start();
where queue
is Mike Bostock's queue lib for asynchronous file queueing. When I try to test the script, I get in the console:
Inside start: Object { var0 = "something", var1={...}, more...}
Inside setup: Window testpage.html
TypeError: this.process_data is not a function
So, invoking setup
from q.await
makes it loose the object's scope (or whatever this is called in JavaScript...). How can I avoid this? I have also tried using a proxy object like:
this.start = function() {
console.log("Inside start:", this);
var q, proxy;
q = queue().defer(d3.json, "config.json")
.defer(d3.csv, "data.csv");
proxy = this.setup;
q.await(proxy);
}
to no avail!
Upvotes: 2
Views: 90
Reputation: 27843
The value of this
is determined by how you call the function that contains it. You have no control over how the setup
function is called, since it is called inside the q.await
function.
When you do q.await(this.setup)
, you pass a reference to the function setup, but "lose" any connection to your namespace. You need to bind the function to the namespace for it to have the proper this
value:
q.await(this.setup.bind(this));
Even better, since all your functions work only if this
is the namespace, you should bind them to the namespace like this:
this.start = function() {
// body
}.bind(this);
// usage:
q.await(this.setup);
And now wherever you pass them, they will have the correct this
inside.
Note: in this situation, bind
works something like this:
this.start = function() {
var namespace = this;
q.await(function(){ namespace.setup(); });
}
Upvotes: 2