Function.prototype.bind

Jürg Lehni lists at scratchdisk.com
Fri Apr 30 06:32:15 PDT 2010


After having used my own version of an implementation of Function.prototype.bind for about 4 years now I recently became aware of the one that appears to now be standardised in ES5.

The following page suggests its definition stems from the Prototype.js library: <http://wiki.ecmascript.org/doku.php?id=proposals:static_generics> 

The page argues that "if we do this, we should emulate Prototype, including its 'pre-args' feature, since it actually hacks on Function.prototype and it's a de-facto standard".

I have to disagree, especially with this so-called 'pre-args' feature, which prepends arguments to the final argument list. There are quite a few libraries out there, Prototype.js is only one of many, and seems to have lost significance over the past years. Calling it a de-facto standard and shaping parts of the future ECMAScript standard after it in order to remain compatible with it seems questionable. There are other areas were similar considerations seem to have played a role, the oddly named Object.keys() comes to mind.

The current implementation of bind() uses the first argument as the bind object, and the ones after as the arguments passed to the bound function. If the bound function then is called with passed arguments itself, these are appended to the argument list that was defined in the call of bind(). I find this confusing and wonder if there is any real world use for this? I have no experience with Prototype.js but never saw the need for such a feature. Here an example to illustrate the functionality of bind():

function test() {
	alert(Array.prototype.slice(arguments).join(', '));
}

test(1, 2, 3); // "1, 2, 3"

var test2 = test.bind(this, 1, 2, 3);

test2(); // "1, 2, 3"

test2(4, 5); // "1, 2, 3, 4, 5"

Am I the only one thinking it is wrong that the first and second argument to a function then actually end up being the 4th and the 5th when the originally defined function is called? If test() was defined differently and would do more than simply join the arguments to one string but actually used parameter names to perform something with them, I would find the resulting code to be pretty hard to read and understand.

An alternative definition could have been that the bind() call defines the default arguments that are passed to the bound function, which can be overridden when the bound function is called. The above example would end up as:

test2(4, 5); // "4, 5, 3"

This seems more logical to me, and less prone to errors.

Another issue I have with bind() is that there is no alternative version of it that receives an array for the arguments passed to the function, in analogy to the differences between apply() and call(). If I had to choose only one of these two, I would opt for apply(), as it offers far more flexibility. A bind() function defined to receive the arguments as an array would still allow things like the above example with very little more syntax, while offering many other advantages at the same time:

var test2 = test.bind(this, [ 1, 2, 3 ]);

or:

var args = [ 1, 2, 3 ];

if (passMoreArgs)
	args.push(4, 5, 6);

var test2 = test.bind(this, args);

I hope this serves as an understandable illustration.

With many of the recent additions to the language I continue to be a bit puzzled by the decision making process. I think things should not just be taken over from a library that is at one point in fashion. Functionality should be discussed and formulated in a way that feels true to the philosophies in the ECMAScript language. Such libraries are good because they point out things currently missing in the language. But they should be seen as starting points for a dialogue, not as the final word.

Jürg





More information about the es-discuss mailing list