#219 enhancement
Juriy Zaytsev

Improved Function#methodize

Reported by Juriy Zaytsev | July 12th, 2008 @ 07:13 AM

Continuing with Function.prototype.* optimizations, here's a "smarter" Function#methodize.

There are 34 Element methods in prototype.js that accept no arguments (more than a half of all) - Element.show, Element.hide, Element.visible, etc.

When extending DOM Elements, all these methods are "methodized" by one pattern - the one that accounts for extra arguments. Array.prototype.concat and $A are the usual party poopers when it comes to performance. By returning a "simpler" function when methodizing a parameter-less method, we can boost the speed of the entire library.

Function.prototype.methodize = function(noArgs) {
  if __method = this;
  return this._methodized = (noArgs === true)
    ? function() { return __method.call(null, this) }
    : function() { return __method.apply(null, [this].concat($A(arguments))) };
}

Comments and changes to this ticket

  • Juriy Zaytsev

    Juriy Zaytsev July 12th, 2008 @ 07:23 AM

    • → State changed from “new” to “enhancement”

    Some numbers from FF2. I'm sure IE yields even better increase.

    Function.prototype.methodize2 = function(noArgs) {
       var __method = this;
      return this._methodized = (noArgs === true)
        ? function() { return __method.call(null, this) }
        : function() { return __method.apply(null, [this].concat($A(arguments))) };
    }
    
    document.body.show1 = Element.Methods.show.methodize();
    document.body.show2 = Element.Methods.show.methodize2(true);
    
    console.time('old');
    for(var i=0; i<1000; i++) document.body.show1();
    console.timeEnd('old');
    
    console.time('new');
    for(var i=0; i<1000; i++) document.body.show2();
    console.timeEnd('new');
    
    // old: 57ms
    // new: 30ms
    
  • Juriy Zaytsev

    Juriy Zaytsev July 20th, 2008 @ 01:17 AM

    Attaching an alternative (better) patch which improves methodize, wrap and curry with using a safer technique. Speed improvements are as usual 30%+

  • John-David Dalton

    John-David Dalton July 23rd, 2008 @ 03:48 PM

    • → Assigned user changed from “Juriy Zaytsev” to “Andrew Dupont”
    • → Milestone changed from “” to “1.6.0.3”
  • John-David Dalton
  • Mark Caudill

    Mark Caudill August 30th, 2008 @ 10:19 PM

    For curry, isn't that pointless because !arguments.length returns this anyway?

    
         if (!arguments.length) return this;
         var __method = this, args = $A(arguments);
         return function() {
    -      return __method.apply(this, args.concat($A(arguments)));
    +      return arguments.length
    +        ? __method.apply(this, args.concat($A(arguments)))
    +        : __method.apply(this, args);
    
  • Juriy Zaytsev

    Juriy Zaytsev August 31st, 2008 @ 04:51 PM

    @Mark

    Those are two different arguments : )

    First line in curry ensures that when no arguments are passed into curry, the function is returned as it is:

    
    function foo(){};
    foo.curry(); // => returns `foo` function
    

    The forking of returned function, on the other hand, is to skip unnecessary concatenation when no arguments are passed into a function returned by curry:

    
    function foo(a,b){ return [a, b] };
    var curried = foo.curry('bar');
    
    // no arguments were given, no need to concat, returns ['bar', undefined]
    curried();
    
    // arguments were given, concat them with curried ones, returns ['bar', 'baz']
    curried('baz');
    
  • Tobie Langel

Please Login or create a free account to add a new comment.

You can update this ticket by sending an email to from your email client. (help)

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

The Prototype JavaScript library.

Shared Ticket Bins

Tags