tnhu / jsface

Small, fast, elegant, powerful, and cross platform JavaScript OOP library. Support main(), singleton, super call, private, mixins, plugins, AOP and more.
MIT License
301 stars 46 forks source link

Introduce Class.create() function #16

Closed AntonBaukin closed 9 years ago

AntonBaukin commented 11 years ago

Well known, that new operator doesn't allow you to invoke it as Function.apply(this, arguments). To create instances in places where the actual number of arguments is not known, please, introduce Class.create() function. It may be used like this:

var Person = Class(Human, { ... })

function() { //<-- factory method return Person.create.apply(Person, arguments) }

or simply like this:

function() { return Person.create(arguments) }

or directly instead of new operator (as a 'statis' constructor):

var p = Person.create(id, name, ...)

tnhu commented 11 years ago

Anton, can you give more details about "new operator doesn't allow you to invoke it as Function.apply(this, arguments)"?

My perception about Class.create is we end up having two ways to create instances. Personally, I would avoid to introduce more than one.

You can easily have this effect by creating a base class which defines create as a static method. All other classes inherit (directly or indirectly) this class.

var Base = Class({
  $statics: {
    create: function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) {
      var instance = new this(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); // kind of urgly here :)
      return instance;
    }
  }
});

var Person = Class(Base, {
    constructor: function(id, name) {
        this.id   = id;
        this.name = name;
    },

    toString: function() {
        return this.id + '/' + this.name;
    }    
});

var person = Person.create(1, 'Anton');
person.toString();                       // '1/Anton'

Thoughts?

AntonBaukin commented 11 years ago
Hello! 
  If you add create() into $statics, the function will be available
  for the instances. The implementation itself is well-known:     Class.create = function()    {        var args = arguments;        function C()        {            Class.apply(this, args)        }        C.prototype = Class.prototype;        //maybe ~> Object.extend(C, Class)        return new C();    }
  Tan Nhu пишет:

  Anton, can you give more details about "new operator doesn't
    allow you to invoke it as Function.apply(this, arguments)"?
  My perception about Class.create is we end up having two ways
    to create instances. Personally, I would avoid to introduce more
    than one.
  You can easily have this effect by creating a base class which
    defines create as a static method. All other classes inherit
    (directly or indirectly) this class.

    var Base = Class({

$statics: { create: function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) { var instance = new this(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); // kind of urgly here :) return instance; } } });

var Person = Class(Base, { constructor: function(id, name) { this.id = id; this.name = name; },

toString: function() {
    return this.id + '/' + this.name;
}    

});

var person = Person.create(1, 'Anton'); person.toString(); // '1/Anton'

  Thoughts?
  —
    Reply to this email directly or view
      it on GitHub.
tnhu commented 11 years ago

In case you want create() to be visible on class level only, I suggest to use $ready plugin on Base class. Again, I'm not convinced to have create() in core JSFace as it introduces another (slower) mechanism to initialize an instance beyond new.

var Base = Class({
  $ready: function(clazz, parent, api) {
    clazz.create = function() {
      var C        = function() {}, 
          instance = new C();

      jsface.extend(C, this);
      this.apply(instance, arguments);

      return instance;
    }
  }
});

var Person = Class(Base, {
    constructor: function(id, name) {
        this.id   = id;
        this.name = name;
    },

    toString: function() {
        return this.id + '/' + this.name;
    }    
});

var person = Person.create(1, 'Anton');
person.toString();                       // '1/Anton'