3

I want to create a series of objects that inherit or copy instance properties from a base object. This has led me to a decision about which pattern to use, and I wanted to ask your opinions about which method was "better".

//APPLY:
// ---------------------------------------------------------
//base object template
var base = function(){
   this.x = { foo: 'bar'};
   this.do = function(){return this.x;}
}

//instance constructor
var instConstructor = function (a,b,c){
   base.apply(this);//coerces context on base
   this.aa = a;
   this.bb = b;
   this.cc = c;
}

instConstructor.prototype = new base();

var inst = function(a,b,c){
    return new instConstructor(a,b,c);
}

//CLONE   
// --------------------------------------------------------- 
function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}    

var x = {foo: 'bar'};

function instC(a,b,c){
     this.aa = a;
     this.bb = b;
     this.cc = c;
     this.x = clone(x);
};

instC.prototype.do = function(){
    return this.x;
}

they both achieve the same thing, namely unique instance properties based on a common template - the question is which one is more "elegant"

sunwukung
  • 2,815
  • 3
  • 41
  • 56
  • Does it really work to set `inst.prototype = ...` _before_ you've assigned `inst` equal to the function on the next line? Should that be `instConstructor.prototype = ...` – nnnnnn Nov 10 '11 at 10:59
  • good spot - sorry - that was a typo – sunwukung Nov 10 '11 at 11:53

2 Answers2

2

By the sound of your questions it looks like you are looking for something akin to Object.create. This function can be used to create a new object that has an object of your choice as a prototype.

//for old browsers without Object.create:
var objCreate = function(proto){
    function F(){};
    F.prototype = proto;
    return new F();

As for the comparison with the clone method, they do different things so you have to choose what is more appropriate.

Using prototypes will reflect changes on the parent object on the child objects.

a = {x:1};
b = Object.create(a);
a.x = 2;
//b.x is now 2 as well

You also have to be careful about using methods that have this. Depending on what you do you can have unwanted consequences if you use too much prototypal inheritance.

a ={
   x: 1,
   foo: function(){ this.x += 1 }
}
b = Object.create(a);
b.foo();
//a.x does not change

On the other hand, cloning clones stuff so you can be sure that the objects won't interfere with each other in any way. Sometimes this is what you want.

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • yup, been looking at that method too, but ran into some issues: http://stackoverflow.com/questions/8073055/minor-drawback-with-crockford-prototypical-inheritance/8076515#8076515 – sunwukung Nov 10 '11 at 11:13
  • Getting a handle on an object's prototype is finicky unless you can use things like the new getPrototypeOf or __ptoto__. Depending on what you want to do also copying the methods from the object to be cloned might also work. – hugomg Nov 10 '11 at 11:53
0

OK, so i've given this some further thought - and the answer stems from the use case. Where clone is copying properties into a given scope, apply is changing the scope surrounding the property. The former is better for mixins, the latter for inheritance.

sunwukung
  • 2,815
  • 3
  • 41
  • 56