Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

1 decade ago by amadeus

I found the implementation of Function.bind included in ImpactJS doesn't actually work with supplied arguments.

Current Implementation:
Function.prototype.bind = Function.prototype.bind || function(bind) {
	var self = this;
	return function(){
		var args = Array.prototype.slice.call(arguments);
		return self.apply(bind || null, args);
	};
};

The problem with this implementation is that 'arguments', being a reserved keyword, doesn't actually transfer through on the closure since the returned method when executed uses it's own local version of arguments, which is obviously empty. Furthermore, even if arguments would get passed along, the first arg would be the scope and thus break the returned series of arguments, since scope would be first.

There are a couple possible fixes, one would be actually creating a local variable that's equal to a slice of arguments starting at index 1, the other, and probably better fix would be to use the MDN solution since it's considered ECMA script compliant:

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

1 decade ago by amadeus

Here are the possible solutions.

// ECMA Script Compliant
Function.prototype.bind = Function.prototype.bind || function (oThis) {
	if (typeof this !== "function") {
		// closest thing possible to the ECMAScript 5 internal IsCallable function
		throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
	}

	var aArgs = Array.prototype.slice.call(arguments, 1),
		fToBind = this,
		fNOP = function () {},
		fBound = function () {
			return fToBind.apply(this instanceof fNOP
				 ? this
				 : oThis,
				 aArgs.concat(Array.prototype.slice.call(arguments)));
		};

	fNOP.prototype = this.prototype;
	fBound.prototype = new fNOP();

	return fBound;
};

// Quick fix based on current implementation
Function.prototype.bind = Function.prototype.bind || function(bind) {
	var self = this,
		args = Array.prototype.slice.call(arguments, 1);

	return function(){
		return self.apply(bind || null, args);
	};
};

1 decade ago by KirbySaysHi

You're right, but I think you're talking about partial application of arguments. When I read your post, I thought you were talking about arguments on the returned, bound function, but you mean at binding time, correct? If that's the case, then yes, the shim Impact provides is in the wrong here.

I have a feeling that most usages of bind are to preserve scope, as opposed to partial application, which is why this wasn't noticed before.

Your second "quick fix" though isn't quite correct, since now you're discarding the arguments passed into the bound function at call time, while preserving the arguments passed in at binding time.

Try this:

Function.prototype.bind = Function.prototype.bind || function(bind) {
    var self = this,
        slice = Array.prototype.slice
        args = slice.call(arguments, 1);

    return function(){
        return self.apply(bind || null, args.concat( slice.call(arguments) ) );
    };
};

Either way, you're much better off using either the shim you initially posted from MDN, or the one from es5-shim.

1 decade ago by quidmonkey

Are you trying to curry a function?

1 decade ago by amadeus

I am assuming this is replicating an ECMA Script Function.bind since Dominic's implementation first checks for the existence of Function.bind.

If Function.bind exists (say Chrome) you're going to get a different implementation from a browser that doesn't support Function.bind (say, earlier versions of Safari).

So yes, my quick fix solution was really only a partial fix since it would break other types of functionality.

1 decade ago by dominic

Thanks for reporting! I didn't notice the difference - in blindly copied this function from MooTools (I think) without giving it a second thought.
Page 1 of 1
« first « previous next › last »