I am using node.js. I have this handlers.js file:
exports.Handlers = function(prefix) {
this.prefix = prefix;
this.db = new DBInstance();
};
exports.Handlers.prototype.getItemById = function(id) {
var item = this.db.getItemById(id, function(error, item) {
item.name = this.prefix + item.name;
...
...
});
};
When I call:
var h = new Handlers();
h.getItemById(5);
I get an error since the context isn't the Handlers and this.prefix doesn't exists. I can fix it using this:
exports.Handlers.prototype.getItemById = function(id) {
var scope = this;
var item = this.db.getItemById(id, function(error, item) {
item.name = scope.prefix + item.name;
...
...
});
};
Is there any better way to pass the context to the callback? What is the nodejs common way to pass the context to the callback?
Node implements ECMAScript 5, which has Function.bind()
.
I think that is what you are looking for.
exports.Handlers.prototype.getItemById = function(id) {
var item = this.db.getItemById(id, (function(error, item) {
item.name = this.prefix + item.name;
...
...
}).bind(this)); //bind context to function
};
This works, however when using a closure as a callback, like you are doing, the most common way this is done is by storing the context in a variable that can be used in the closure.
This method is more common because many times callbacks can be deep and calling bind
on each callback can be heavy; whereas defining self
once is easy:
SomeObject.prototype.method = function(id, cb) {
var self = this;
this.getSomething(id, function(something) {
//self is still in scope
self.getSomethingElse(something.id, function(selse) {
//self is still in scope and I didn't need to bind twice
self.gotThemAll(selse.id, cb);
});
});
};
This problem is not related to Node.js, it's a general problem in JavaScript - and you already figured out the usual solution in JavaScript: Bind the this
context to another variable (the one that you called scope
), and use that within the callback to access the outer context.
Common names for this variable include that
and self
.
There may be a solution in ECMAScript 6 (codename "harmony") with the so-called fat-arrow operator that binds a function to an outer context. If you want to play with it today you might want to check out TypeScript, a pre-compiler for JavaScript made by Microsoft which focuses on ES6-compatible syntax. Then your callback becomes something such as
foo(() => { console.log(this.bar); });
instead of:
var that = this;
foo(function () { console.log(that.bar); });
Just for the sake of completeness: jQuery's (and other frameworks) bind
function generally works similar. See http://api.jquery.com/bind/ for an example.
HTH.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With