#286 enhancement
Giso Stallenberg

Construct a class with arbitrary number of arguments

Reported by Giso Stallenberg | August 16th, 2008 @ 04:45 PM | in 1.6.1

Adding the next piece of code to Class.Methods will make it possible to construct a class with an arbitrary number of arguments.


Class.Methods = {
  addMethods: function(source) {
    // ...
  },

  construct: function(args) {
    var init = this.prototype.initialize; // store original initialize
    this.prototype.initialize = Prototype.emptyFunction; // temporary empty initialize
    var instance = new this(); // create instance
    instance.initialize = this.prototype.initialize = init; // restore initialize
    instance.initialize.apply(instance, $A(args) ); // apply initialize
    return instance; // return new object
  }
};
// ------
// now we can use:
var someInstance = SomeClass.construct(["arg1", "arg2"]);

This can be very useful when you have "factory"-methods in which you don't need to know the number of arguments, as in:


function createClass(className) {
  var args = $A(arguments); args.shift();
  return window[className].construct(args);
}

Comments and changes to this ticket

  • Juriy Zaytsev

    Juriy Zaytsev August 16th, 2008 @ 07:04 PM

    • → Milestone changed from “” to “1.6.1”
    • → State changed from “new” to “enhancement”
    • → Assigned user changed from “” to “Juriy Zaytsev”

    That's clever.

    The only thing I'm not sure about is assigning of initialize property directly to an instance. This seems unnecessary and somewhat obtrusive. When "restoring" a prototype.initialize from init, why not call init directly via apply (and not assign it to an instance, but leave it on prototype as it was before)?

    
    Class.Methods.construct = function(args) {
      var init = this.prototype.initialize;
      this.prototype.initialize = Prototype.emptyFunction;
      var instance = new this();
      this.prototype.initialize = init;
      init.apply(instance, $A(arguments.length == 1 ? args : arguments));
      return instance;
    };
    

    This also allows to optionally pass arguments the usual way, rather than explicitly passing an array:

    
    Person.construct('Ivan', 'Petrovich');
    // or
    Person.construct(['Jan', 'Kowalski']);
    
  • Giso Stallenberg

    Giso Stallenberg August 16th, 2008 @ 07:43 PM

    I agree with you on applying initialize on the instance rather than restoring it. I don't agree on the arguments length check, because it will also split the first argument when it's meant to be an array

    
    var someClass = Class.create({
      initialize: function(someArray) {
        this.someArray = someArray;
      }
    });
    var someInstance = someClass.construct(["foo", "bar"]);
    
    someInstance.someArray
    // --> foo
    // --> expected ["foo", "bar"]
    
  • Juriy Zaytsev
  • Giso Stallenberg

    Giso Stallenberg August 18th, 2008 @ 11:17 AM

    
    Class.Methods.construct = function(args) {
      var init = this.prototype.constructor;
      this.prototype.constructor = Prototype.emptyFunction;
      var instance = new this();
      this.prototype.constructor = init;
      init.apply(instance, $A(args) );
      return instance;
    };
    

    is actually more correct I think and avoids an extra call to a function

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

People watching this ticket