#286 enhancement
Giso Stallenberg

Construct a class with arbitrary number of arguments

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

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

    • State changed from “new” to “enhancement”
    • Assigned user set to “Juriy Zaytsev”
    • Milestone set to 1.7

    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

  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 01:55 AM

    • Tag changed from class, enhancement, function, needs_tests to function, needs_tests, section:lang

    [not-tagged:"class" tagged:"section:lang" bulk edit command]

  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 02:07 AM

    • Tag changed from function, needs_tests, section:lang to needs_tests, section:lang

    [not-tagged:"function" bulk edit command]

  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 02:26 AM

    • Tag changed from needs_tests, section:lang to missing:tests, section:lang

    [not-tagged:"needs_tests" tagged:"missing:tests" bulk edit command]

  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 03:36 AM

    • Tag changed from missing:tests, section:lang to needs:tests, section:lang

    [not-tagged:"missing:tests" tagged:"needs:tests" bulk edit command]

  • T.J. Crowder

    T.J. Crowder November 16th, 2009 @ 04:50 PM

    • Assigned user cleared.

    [responsible:none bulk edit command]

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

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

Pages