Bind more arguments of an already bound function in Javascript

Martin Pecka picture Martin Pecka · Jan 4, 2014 · Viewed 26.2k times · Source

I try to sort my thoughts about how javascript's bind() works.

I see that if I do

var f = function (a) { ... }
var g = f.bind(obj);
g(1)

then f is called with obj as this and 1 as a.

What I thought is g is a wrapper function around f.

But when I do

var f = function (a) { ... }
var g = f.bind(obj);
g.call(1)

then f is called with 1 as this and a undefined.

So it seems g is not just a simple wrapper, but call somehow differentiates between normal and bound functions.

One more thing is I cannot partially apply a function more times.

var f = function (a) { ... }
var g = f.bind(obj);
var h = g.bind(1);
h();

Then f is called with obj as this and a undefined.

What is the cause of this behavior?

Edit

The constructs in this question are actually wrong, see the accepted answer on what they should look like (in general I haven't noticed that call and bind do always need the context argument as the first argument).

Answer

ZER0 picture ZER0 · Jan 4, 2014

Once you bound an object to a function with bind, you cannot override it. It's clearly written in the specs, as you can see in MDN documentation:

"The bind() function creates a new function (a bound function) with the same function body (internal call property in ECMAScript 5 terms) as the function it is being called on (the bound function's target function) with the this value bound to the first argument of bind(), which cannot be overridden."

That means, also if you do:

g.call(1);

You will get obj as this, and not 1 – on the browsers that follows the specs.

You can of course binds multiple arguments, so:

var sum = function(a, b, c) { return a + b + c };
var sumAB = sum.bind(null, 1, 5);
var sumC = sumAB.bind(null, 2);

console.log(sumC());

But the context object will be always the one specified with the first bind, because it cannot be overwritten.

Just to avoid confusion, the first argument of call is the context object (this), then you will have the rest of the argument.

It means:

var obj = { foo: function(bar) { console.log(bar) } };

obj.foo('hello');

// equivalent to:
var foo = obj.foo;

foo.call(obj, 'hello');

Hope it helps.