bind()
A lot of useful operations in JS (such as setTimeout(), or events) are ones that require a function. For example, we can do, in a JS-supporting browser:setTimeout(foo, 3000);
... and foo() will be called in three seconds. This has obvious myriad uses. However, what if we have an object:
var a = {
b: 5,
c: function(d) {
return this.b + d;
}
};
... and we want to call a.c(3)? A common newbie mistake is to do: setTimeout(a.c(3), 3000); Unfortunately, this is a no-go. Arguments are evaluated before the function is called, so the result is that we're actually calling:
setTimeout(8, 3000);
... which doesn't really make sense. Even if we ignore the arguments for now and just attempt:
setTimeout(a.c, 3000);
... it will still fail, because only the function is passed, and not its context -- within the function, when it is executed, 'this' will be the global object (see Context - the Magic Argument). The solution is to use a closure to pass in both the context and arguments:
setTimeout(function() { return a.c(3); }, 3000);
This can involve quite a bit of boilerplate, especially in certain situations, and quickly gets tiresome (not to mention being rather unintuitive). Thankfully, ECMAScript is a functional language: we can pass functions around as variables and arguments (and in fact have been doing so already, here). This means we can write a simple function to abstract this away:
function bind(obj, fun, args) {
return function() {
if (obj === true)
obj = this;
var f = typeof fun === "string" ? obj[fun] : fun;
return f.apply(obj, Array.prototype.slice.call(args || [])
.concat(Array.prototype.slice.call(arguments)));
};
}
This function, as you can see, takes three arguments: an object to use as context (or true for default context), a function (or name of that function to lookup on the object), and an optional array of arguments. It returns a function which simply returns the value of the original function applied to that context and those arguments, using Function.prototype.apply(). The result is that our setTimeout() example from above can be written much more tersely and intuitively as:
setTimeout(bind(a, "c", [3]), 3000);
By Twey.