Function.prototype.bind - javascript

I've got pretty interesting question about EcmaScript-5 Function.prototype.bind implementation. Usually when you use bind, you do it this way:
var myFunction = function() {
alert(this);
}.bind(123);
// will alert 123
myFunction();
Okay so that's cool, but what is suppose to happen when we do this?
// rebind binded function
myFunction = myFunction.bind('foobar');
// will alert... 123!
myFunction();
I understand that it's completely logical behavior in terms of how Function.prototype.bind is implemented (https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind). But in real life conditions it's completely useless behavior isn't it? The question is: is it bug or feature? If it's a bug, why it's nowhere mentioned? If it's a feature, why then Google Chrome with native "bind" implementation behaves absolutely the same way?
To make it more clear, what in my opinion would make more sense, here is the code snippet that implements Function.prototype.bind a little bit differently:
if (!Function.prototype.bind) {
Function.prototype.bind = function() {
var funcObj = this;
var original = funcObj;
var extraArgs = Array.prototype.slice.call(arguments);
var thisObj = extraArgs.shift();
var func = function() {
var thatObj = thisObj;
return original.apply(thatObj, extraArgs.concat(
Array.prototype.slice.call(
arguments, extraArgs.length
)
));
};
func.bind = function() {
var args = Array.prototype.slice.call(arguments);
return Function.prototype.bind.apply(funcObj, args);
}
return func;
};
}
So now try this:
// rebind binded function
myFunction = myFunction.bind('foobar');
// will alert... "foobar"
myFunction();
In my opinion, replacing "this" makes more sense...
So what do you guys think about it?

The precedent for Function.prototype.bind was the implementation of the idea in various JS frameworks. To the best of my knowledge, none of them allowed this-binding to be changed by subsequent binding. You might as well ask why none of them allowed this-binding changing, as to ask why ES5 doesn't allow it.
You're not the only person I've heard who thought this odd. Chris Leary, who works on Mozilla's JS engine (as I do), thought it a bit odd, raising the issue on Twitter a couple months ago. And in a somewhat different form, I remember one of the Mozilla Labs hackers questioning if there were some way to "unbind" a function, to extract the target function from it. (If you could do that, you could of course bind it to a different this, at least if you could also extract the bound arguments list to also pass it along.)
I don't remember the issue being discussed when bind was being specified. However, I wasn't paying particularly close attention to the es-discuss mailing list at the time this stuff was hashed out. That said, I don't believe ES5 was looking to innovate in the area much, just "pave a cowpath", to borrow a phrase.
You might possibly be able to propose some introspective methods to address these concerns to es-discuss, if you wrote a sufficiently detailed proposal. On the other hand, binding is a form of information-hiding mechanism, which would cut against its adoption. It might be worth a try to propose something, if you have time. My guess is the information-hiding concern would block a proposal from being adopted. But that's just a guess that could well be wrong. Only one way to find out...

When you bind a function, you ask for a new function that ignores it's own this pseudo argument and calls the original function with a fixed value for this.
Binding this function another time has exactly the same behaviour. If bind would somehow patch in a new this into it, it would have to special case for already-bound-functions.
In other words, bind works exactly the same on "normal" functions as it works on functions returned by bind, and in the absence of overriding factors, it's good engineering to keep the semantic complexity of a function low - it's easier to remember what bind does to a function if it treats all input functions in exactly the same way, as opposed to treating some input functions specially.
I think your confusion is that you view bind as modifying an existing function, and you therefore, if you modify it again you expect the original function to be modified again. However, bind does not modify anything, it creates a new function with specific behaviour. The new function is a function in it's own right, it's not a magic patched version of the original function.
As such, there is no mystery on why it was standardised or invented the way it was: bind returns a function that provides a new this and prepends arguments, and works the same on all functions. The simplest possible semantic.
Only this way is it actually safe to use - if bind would make a difference between already bound functions and "normal" ones, one would have to test before binding. A good example would be jQuery.each, which passes a new this. If bind would specialcase bound functions, there would be no safe way to pass a bound function into jQuery.each, as this will be overwritten on each call. To fix that, jQuery.each would have to specialcase bound functions somehow.

Related

Is it right to avoid closures using bind in JavaScript?

Are closures too bad for browser's memory?
Is avoiding closures using bind in JavaScript a good way?
Existing code:
var oControl = new Control({
var self = this;
click: function(e){ //closure that's accessing self var
self.performAction();
}
});
I have been told to avoid writing code as shown above. Reason given - a closure is created in the above code. I have been suggested using bind to overcome the above problem.
Modified code:
var oControl = new Control({
var self = this;
click: function(e){ //Not a closure
this.performAction(); //Is this more readable?
}.bind(self)
});
I am not too sure if the modified code is more readable. Somehow, I feel that this is in a way polluted. Probably, there are better ways to avoid closures? But, is there a real need to avoid them in the first place?
I would suggest this:
var oControl = new Control({
click: this.performAction.bind(this)
});
There appears to be no reason in your code for the self variable at all and if the click handler is just going to call your other method, then you may as well use the .bind() without the wrapper function.
FYI, .bind() creates a closure itself so don't be thinking that using .bind() is eliminating a closure. It is eliminating you having to hand-code a closure variable which is what makes it handy to use and makes your code look cleaner.
As for your other questions:
Are closures too bad for browser's memory?
Closures do use some additional memory. Unless you have a zillion of them, that extra memory is not likely material. And, .bind() likely also uses a closure in its implementation (the this pointer has to be stored somewhere).
Is avoiding closures using bind in JavaScript a good way?
.bind() is very useful and you should feel free to use it when it serves your purpose. Whether to use your first block of code with your own closure variable, your second block of code with a wrapper function using .bind() or my suggestion is largely a matter of opinion on coding style and opinion on cleanliness of implementation. All can work fine and there is unlikely to be a meaningful difference in performance or memory usage.

'self = this' vs apply or bind? (Backbone)

Often in my Backbone code I come across situations where I would be passing a closure to some function and lose context of 'this'.
My solution for some time had been to do what I had seen some others do:
var self = this;
this.deferred.done(function () {
self.render();
});
Or actually I switched to _this = this, but that's beside the point. It works, but it feels ugly and I sometimes have to do it quite often. So I'm trying to figure out a better way to do this. I learned I could do this:
this.deferred.done(function () {
this.render();
}.apply(this));
And I think I could also use Underscore to do this:
this.deferred.done(_.bind(function () {
self.render();
}, this));
The apply method seems the most succinct but I feel like it has a side effect (I just don't know what it is yet).
Edit:
Take a look at this JSbin where I use apply similar to as I mentioned:
http://jsbin.com/qobumu/edit?js,console
It works, yet it throws an error at the same time. If I change the apply to bind, it works and doesn't throw an error.
Function.bind is a native method, no need for underscore unless you're coding for antique browsers. Exactly what #dandavis said: this.deferred.done(this.render.bind(this)) (but note that bind can also bind function arguments, not just this)
if you're actually coding for cutting-edge browsers or node.js 4, you can use arrow functions which bind this lexically to whatever it is in the scope where the function is defined, so you could write:
this.deferred.done(() => { this.render() });
Those do different things.
// returns a function with `this` set to what you want.
_.bind(fn, this);
// or
fn.bind(this);
// EXECUTES the function with `this` set to what you want.
fn.apply(this);
So in your case it's not a callback at all. When you use apply you are executing the function when you think you are assigning the callback.
This is why you use bind.

How valuable is it to optimize use of function closures in Javascript?

If have a callback that is activated repeatedly such as the following...
Template.foo.rendered = function() {
$(this.firstNode).droppable({
// other arguments
drop: function() {
// some really long function that doesn't access anything in the closure
}
});
}
Should I optimize it to the following?
dropFunction = function() {
// some really long function that doesn't access anything in the closure
}
Template.foo.rendered = function() {
$(this.firstNode).droppable({
// other arguments
drop: dropFunction
});
}
In this case, the rendered callback is a Meteor construct which runs asynchronously over a DOM node with template foo whenever they are constructed; there can be quite a few of them. Does it help to declare the function somewhere in a global closure, to save the Javascript engine the hassle of keeping track of an extra local closure, or does it not matter?
I don't believe that in modern browsers that there will even be a difference. When creating a closure object, V8 determines what variables your function uses, and if you don't use a variable it won't put it in the closure object(I read this somewhere online a while back, sorry I can't find the link*SEE BELOW*). I assume any browser that compiles JavaScript would do the same.
What will be optimized is the creation of the function. In the second example the drop function is created at the same time as the rendered function, in the first it's re-created every time the rendered is called. If this was in a long for loop that might be worth optimizing.
I personally think the first example is a lot easier to read and maintain. And as I said in a comment on the question you(or the person editing this code in the future) could accidentally overwrite the function variable(in an event handler or something) and you could have a hard to find bug on your hands. I would suggest saying with number 1, or wrapping everything in a self-executing function so dropFunction has a smaller scope and less chance of being overwritten, like so:
(function () {
var dropFunction = function() {
// some really long function that doesn't access anything in the closure
}
Template.foo.rendered = function() {
$(this.firstNode).droppable({
// other arguments
drop: dropFunction
});
}
})();
EDIT: I found the link, it was actually in a blog post about a closure memory leak in Meteor!
http://point.davidglasser.net/2013/06/27/surprising-javascript-memory-leak.html
Here's the portion I mentioned:
JavaScript implementations (or at least current Chrome) are smart enough to notice that str isn’t used in logIt, so it’s not put into logIt’s lexical environment, and it’s OK to GC the big string once run finishes.
I'll start this by saying I don't know anything about meteor :/ but if I'm understanding what happens correctly, basically:
Template.foo.rendered
Gets called repeatedly. When that occurs, you construct and object + define a new function on it "drop" which is eventually invoked. If that is the case, you are better off from a performance perspective defining drop once at parse time. But the benefit probably depends on how often rendered is called.
As for why - I posted something similar here:
Performance of function declaration vs function expressions in javascript in a loop
And I think #soktinpk's answer I think is a great summary.
If you look at the jsperf in the above link it may not initially seem directly applicable, but if my assumed statements above are true it is in fact is - because the question at hand boils down to how expensive is to define a function at runtime vs parse time and are you defining this function at runtime over and over again.
If you look at the performance of the loops where a function is defined at runtime vs the loops where functions are defined at parse time (or defined at parse time and hoisted), the parse time loop run significantly faster.
I believe that the equivalent of what meteor is doing in your example is probably something like this jsperf: http://jsperf.com/how-expensive-is-defining-a-function-at-runtime2
What I have done here is created two loops that simulate your scenario being invoked over and over again. The first invokes a function that creates and object and function and passes it to another function for invocation.
The second creates and object that references a function and passes it to another function for invocation. The difference in performance looks significant (58% in chrome).

Dynamically superseding functions that are not in global scope

I have a script, that based upon specific scenarios, may need to supersede functions to do some processing before eventually calling the original function. (See "'overriding' Javascript Function")
I can get this working in general - here's a basic example using the jQuery plugin Tinyscrollbar (not my intended application, just something quick and easy to illustrate):
(function ($) {
// Snip..
function initalize() {
oSelf.update();
setEvents();
return oSelf;
}
// Snip..
function setEvents() {
(function () {
var oldInit = wheel;
wheel = function (oEvent) {
console.log('Intercept');
oldInit(oEvent);
}
})();
// Original event code, irrelevant to question
}
function wheel(oEvent) {
// Actual function, related to using the mousewheel
}
})(jQuery);
When I scroll the mousewheel, the console prints 'Intercept', and the scrollbar moves as originally defined. Wonderful!
However, the function name is hardcoded, and doesn't live in the global scope, so window[] is unavailable (which I like). Is there any possible combination of black magic, 'new Function()', and/or other way to loop through a potential list of function names (which may change based on other logic) and encapsulate them in this (or similar-in-spirit) manner?
Thanks in advance!
Unfortunately, there's no way to enumerate or dynamically access members in a scope object (with the convenient exception of the global scope/window object)
So you'd need to rephrase your code a bit. Instead of having free-floating functions in your outer function, have objects with methods on them. That'd make replacing those methods much easier.
There's some additional trickiness if you modify your functions after you started assigning them as event handlers or whatever. If you happen to use some kind of bind() wrapper around those functions, the correctness of your behavior will depend a lot on that bind() function.
Specifically, if you want the replacement method to retroactively become the method called for any event handler or callback it was assigned to, you'll want to use a bind() wrapper that takes a context object and a string meant to be the function name rather than a context object and a function reference. (and make sure that bind() doesn't resolve that string early to shave some ms on each calls.)
If don't don't want the retroactive behavior, you still have to make sure you don't have some bind()-ed version of the original method floating around and still being used for new callbacks after your replacement happened.

How to pass 'this' along with a function?

I want to delegate some function calls from one object to another:
objA.feature = objA.component.feature;
(Assuming feature is supposed to be a function both in objA and in its component)
But that clearly doesn't work, because the reference to this gets stripped from the function and ends up being a completely different object when it gets called (it actually is objA instead of objB.component).
You need to write something like this in order to get it to work:
objA.feature = function() {
objA.component.feature.apply(objA.component, arguments);
};
Is there a shorter (idiomatic) way to do that?
There's a function called "bind" on the Function prototype in newer runtimes:
var newFunc = someFunc.bind(somethingThatShouldBeThis);
will make this refer to "somethingThatShouldBeThis" when "newFunc" is called.
You can steal code from something like the Functional library to provide a "bind" function in environments that lack a native one.
edit — here's the code from Functional:
Function.prototype.bind = function(object/*, args...*/) {
var fn = this;
var args = Array.slice(arguments, 1);
return function() {
return fn.apply(object, args.concat(Array.slice(arguments, 0)));
}
}
Pretty simple, eh? It just returns a function back to you that, when invoked, will call the first argument as a function, and also pass along whatever arguments you pass in to the result (that is, to "newFunc" in the example above). The main wrinkle is that this one also saves extra arguments passed in originally, which can sometimes be handy.
Here is a great article on scope:
Binding Scope in JavaScript
However, most JavaScript frameworks (MooTools, jQuery) have built in methods for this. jQuery uses "proxy" and MooTools uses "bind", so be sure to check the documentation of whatever framework you're using.
Your best bet is to use a createDelegate-style method like some of the frameworks do. A bare-bones implementation was posted on OdeToCode a few years ago.

Categories