As I suspect is common with many Prototype shops, over here at
Zenbe.com, we're making HEAVY use of Function#bind(). We've been
using a custom version of the bind() method for a while now, and I've
recently added a couple enhancements that I'd like to get people's
opinions on - especially that of the Prototype team.
I've attached a commented version of our implementation below (we run
this after importing the Prototype library, so it just overwrites the
Prototype code). The motivation for this implementation is as
follows:
- bind() is so ubiquitous for us that performance is a top priority.
We're willing to have a bit more code here to make things run faster.
In particular, 99% of our use of bind() is simply to bind a function
to an object, without binding any arguments (e.g. "...bind
(someObject)"). So special-casing that situation makes sense.
- Stepping through bound functions is painful because you constantly
have to step-into/out-of the $A method. It's possible to improve
performance *and* make stepping through code easier by inlining the
code that sets up the args array.
- Inspecting functions created by bind() (e.g. "someFunction.toString
()") is never helpful. Provide a way to "unbind" a function to get at
the original method.
Aside from the obvious increase in code size (which isn't *that* much
when the code is compacted - adds ~100-150 bytes), are there any
disadvantages/weaknesses to this implementation? Would it make sense
to migrate some or all of these changes into the Prototype codebase?
=======================
Object.extend(Function.prototype, {
bind: function(object) {
var __method = this, __f;
// Special case: No args or object being bound - just return
this function
if (arguments.length < 2 && arguments[0] === undefined) return
this;
if (arguments.length == 1) {
// Special case: No args are being bound - don't bother
creating a new
// args structure
__f = function() {
return __method.apply(object, arguments);
};
} else {
// General case: Basically do what the native Prototype
implementation
// does, but be as as efficient as possible, and make it
trivial to
// step through in a debugger.
var args = $A(arguments), l = args.length-1;
args.shift();
__f = function() {
// Set up the args array. Note that we recycle the args
array,
// rather than creating a new one. Also do all this on ONE
line so
// it only takes one click to step over in a debugger.
var ll = arguments.length; args.length = l + ll; while
(ll--) args[l+ll] = arguments[ll];
return __method.apply(object, args);
};
}
// Finally, keep a reference to the original function so we can
// unbind() (below) as needed.
__f._boundFunction = this;
return __f;
},
unbind: function() {
var orig = this;
while (orig._boundFunction) orig = orig._boundFunction;
return orig;
}
});
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Prototype & script.aculo.us" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/prototype-scriptaculous?hl=en
-~----------~----~----~----~------~----~------~--~---