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 prototype-scriptaculous@googlegroups.com
To unsubscribe from this group, send email to 
prototype-scriptaculous+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/prototype-scriptaculous?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to