From my reading it appears that when extending a Backbone.js class such as Model, a fairly common pattern is to call _.bindAll in the constructor as follows (see https://raw.github.com/eschwartz/backbone.googlemaps/master/lib/backbone.googlemaps.js):
GoogleMaps.Location = Backbone.Model.extend({
constructor: function() {
_.bindAll(this, 'select', 'deselect', 'toggleSelect', 'getLatLng', 'getLatlng');
// etcetera
I do understand why this gets done, however the need for explicitly passing method names to _.bindAll seems to be a maintenance issue -- if you add new methods, you have to remember add them as an argument to _.bindAll as well.
Earlier today I posted a somewhat verbose solution to this here: https://stackoverflow.com/a/17977852/34806
However, shouldn't the following simple technique altogether avoid the need to call _.bindAll? And that is, instead of the customary way of assigning "custom" methods, to instead attach them all to "this" within the constructor:
constructor: function() {
this.foo = function() {};
this.bar = function() {};
}
Are there any downsides to this technique?
Your technique doesn't work, you still need to bind those methods like any other. Or use something like var this = self but then those methods cannot be used in sub-classes or anywhere else for that matter.
Just get rid of the bindAll altogether and bind just in time when you need it, e.g. when passing a method as a callback somewhere. It should be far easier on the maintenance because the chore is localized. Forgetting to bind when passing a method as a callback should eventually feel wrong like forgetting to use var.
This that you need to explicitly pass in the names of the methods to _BindAll you want to bind is actually a pretty recent change as of underscore.js 1.5.0 - 7/6/13, if you look at the change log for that release you'll see the following reason given for that change
Removed the ability to call _.bindAll with no method name arguments.
It's pretty much always wiser to white-list the names of the methods
you'd like to bind.
That said it's probably better to do as Esailija says and just bind it just in time by utilizing the optional third parameter which keeps the bindings more localized.
Related
I'm using the Polymer framework and I really enjoy it. But one thing I don't get is the confusion with the this-pointer. When functions get called from for example a button in your custom component the this-pointer points to the custom component. Very logical. But when your function within a custom component is called from something external, for example a callback from an library or a call from another component the this-pointer is something totally different. Why is it in this case not pointing to the custom component where the function is in?
Javascript is a bit of a weird bird when it comes to resolving this, often not doing what you would like. The only saving grace is that it's easy to explain and understand.
A function's this value is set by how it is called. Suppose you have a value val with a method method. If method is called like val.method() then in that call to method then this is val. If you instead do var theMethod = val.method; theMethod(); then for that call, this is something else (the global context object, in browsers this is window).
The solution fortunately is simple. There's a method on functions called bind that returns a new function that has the this immutably baked in. So var theMethod = val.method.bind(val); theMethod() has this bound to val.
In the future for many cases we'll be able to use ES6 Arrow Notation to get this behavior baked in at function definition time, but for now, when passing a method around (e.g. to register an event handler) be sure to bake the this in explicitly with bind.
when using the multitude of utility functions that can accept it. For example:
function foo () {
_.each ([0,1,2,3], function(val) {
// I don't use this in the body
}, this);
}
It seems like one way is more concise and the other is there in case you add code later.
It seems like one way is more concise
Then use that.
in case you add code later.
You ain't gonna need it. Not until later, at least.
The optional parameter adds the context, in other words what 'this' refers to within the callback.
You only need to add it if you want it that way. If you're using a library like backbone, it can come in very handy (eg. when the function is called from within a view object, and you want 'this' to refer to the view).
This is subjective (opinion based) - but only to a degree, don't rush voting to close. Causing some arguments at work as everyone has a different opinion and people are trying to enforce a single way of doing it.
Simple context: when you have the option to save a reference in your closure to the instance or to use a polyfilled Function.prototype.bind, what possible disadvantages do you see to either approach?
To illustrate possible usecases, I just made up some class methods.
Pattern one, saved ref:
obj.prototype.addEvents = function(){
var self = this;
// reference can be local also - for unbinding.
this.onElementClick = function(){
self.emit('clicked');
self.element.off('click', self.onElementClick);
};
this.element.on('click', this.onElementClick);
};
Pattern two, a simple fn.bind:
obj.prototype.addEvents = function(){
// saved reference needs to be bound to this to be unbound
// once again, this can be a local var also.
this.onElementClick = function(){
this.emit('clicked');
this.element.off('click', this.onElementClick);
}.bind(this);
this.element.on('click', this.onElementClick);
};
Pattern two and a half, proto method to event:
obj.prototype.addEvents = function(){
// delegate event to a class method elsewhere
this.element.on('click', this.onElementClick.bind(this));
};
obj.prototype.onElementClick = function(){
this.emit('clicked');
this.element.off('click', this.onElementClick); // not matching due to memoized bound
};
Personally, I am of the opinion that there isn't a single correct way of doing this and should judge on a per-case basis. I quite like the saved reference pattern where possible. I am being told off.
Question recap:
Are there any GC issues to be considered / be mindful of?
Are there any other obvious downsides or pitfalls you can think of on either method?
Polyfill performance or event native .bind vs a saved ref?
My personal preference is to use the saved reference method. Reasoning about the value of this can be very hard sometimes because of how JavaScript treats this.
The bind is nice but if you miss the .bind(this) it looks like a bug.
The latter exposes too much; every time you need a callback you'd need to expose another helper in your API.
There are many ways to use prototyping. I think the most important thing is to pick one and stick to it.
Are there any GC issues to be considered / be mindful of?
Older engines don't infer what variables are still used from the closure and do persist the whole scope. Using bind does make it easy because the context is explicitly passed and the un-collected scope does not contain additional variables.
However, this doesn't make a difference if you're using a function expression anyway (as in patterns #1 and #2).
Are there any other obvious downsides or pitfalls you can think of on either method?
Saving reference:
needs an additional line for declaring the variable, sometimes even a whole new scope (IEFE)
Code can't be easily moved because you need to rename your variable
Using bind:
Easily overlooked on the end of a function expression (just like the invocation of an IEFE), it's not clear what this refers to when reading from top to bottom
Easily forgotten
I personally tend to use bind because of its conciseness, but only with functions (methods) declared elsewhere.
Polyfill performance or event native .bind vs a saved ref?
You don't care.
In your example, you actually don't need that reference to the bound function and the off method. jQuery can take care of that itself, you can use the one method for binding fire-once listeners. Then your code can be shortened to
obj.prototype.addEvents = function(){
this.element.one('click', this.emit.bind(this, 'clicked'));
};
It appears that I am not able to choose between two names for a function:
createFunctionDelegate() and createDelegateFunction().
If it matters, the purpose of the function is that it creates a new function that calls the supplied callback function in the context of the second argument. For example:
var foo = {
init: function() {
setTimeout(App.createFunctionDelegate(this.method, this));
},
method: function() {}
}
When foo.init() is run, it sets a timeout that calls a function which delegates the execution to another function (this.method) called in the context of this (foo).
Anyway, I am not sure which way I should name this function. This is important to me, because I am going to use it in hundreds of places and sometimes I type the one and occasionally the other one. This has to change, I have to choose.
I would use neither of these. What you want to do will be offered by bind() in ES5. I would define Function.prototype.bind if it does not exist already, as described here (but read the description and the possible drawbacks carfully).
This way you make sure you use native functionality if it is supported.
What about just createDelegate(this.method, this)?
As a side note, other places where I've seen this kind of method (and written them), the param ordering is context, function, so createDelegate(this, this.method)
Talking about XBL is not exactly talking about javascript. So I'll create this question that's related to this one, but now about XBL, where I'm not the creator of the root javascript code, but just of the methods and event handlers inside the bindings.
--
In some cases, the this keyword may not refer to the object I expect it to. (recent example: in an key event, in my XBL)
What's the best approach to avoid this kind of mistake?
For now, I'm using always the getElementById (or $.fn from jQuery), but I'm not sure if it's the best approach.
--update
A little bit more details:
Within a XBL method the only way to access the element that was defined in the Xul file (the GUI description file) without using "this" (as it may not be the "this" I expect) is with getElementById, and this makes the code not reusable, so I'm looking for alternatives..
As you've heard elsewhere, the problem is that the this parameter isn't necessarily the object you first thought of, especially when you're talking about event handlers and the like. The best way I found is to write a small function that will bind some object as the this variable and return another function that uses the binding to call the original function.
Take a look at this code:
var bindFunction = function(self, f) {
return function() {
return f.apply(self);
};
};
var foo = function() {
alert(this.hello);
};
var bar = {
hello: "Hello there"
};
var boundFoo = bindFunction(bar, foo);
boundFoo();
What I have is a function called bindFunction that takes an object (called self) and some function, and returns another function that will call the passed-in function applying the self object as the this variable.
The rest of the code is just some test code: a foo function that will alert this.hello, a bar object with a hello member, and how you can bind foo with bar.
In essence, I've taken a function that accepts no parameters and generated another function that will ensure the first is always called with the correct this variable. Ideal for event handlers.
(Sorry, but I know nothing about XBL, so I hope this will be of use.)
If there's not a best answer, a good approach could be use javascript files instead of XBL for the implementation. Looking the Xulrunner source code, looks like most code does this.
But I still would like to use XBL, if there was a way to work fine with it..