Extending prototypes in Javascript - good way?

Jem picture Jem · Feb 12, 2015 · Viewed 17.1k times · Source

I want to validate that the approach I'm using is correct when it comes to extend a prototype - supposing "extend" is the right word.

This topic gets a lot of clones. I'm still trying to properly understand this topic...

The purpose is: - to write clean and good code. - to avoid using frameworks, if possible plain Javascript. - get advice on the clean frameworks that don't twist JS to obtain class-enabled behaviors.

Here is the Parent prototype of my sandbox:

function Parent(){

}

Parent.prototype = {

    "init":function(){

        this.name = "anon";
    },

    "initWithParameters":function(parameters){

        this.name = parameters.name ? parameters.name : "anon";
    },

    "talk": function(){

        console.log('Parent is: ' + this.name);
    }
}

Now the Child prototype - it adds a "position" property and redefines the behaviors:

function Child(){

    Parent.call(this);
}


Child.prototype = new Parent;
Child.prototype.constructor = Child;

Child.prototype.init = function(){

    Parent.prototype.call(this);

    this.setPosition(0, 0);
}

Child.prototype.initWithParameters = function(parameters){

    Parent.prototype.initWithParameters.call(this, parameters);

    if(!this.position){

        this.position = {x:0, y:0};
    }

    this.setPosition(parameters.pos.x, parameters.pos.y);
}

Child.prototype.setPosition = function(x, y){

    this.position.x = x;
    this.position.y = y;
}

Child.prototype.talk = function(){

    console.log('Child is: ' + this.name + ' and location is: ' + this.position.x + ', ' + this.position.y);
}

Is this a good practice? Is there no shorthand to avoid writing "Child.prototype." when overriding a property (using a litteral maybe, like the Parent prototype is written).

I know of J. Resig's Class/extend approach. But I'd rather use Javascript as the prototypical language it is, not make it work as a "class-like behaving class-less OO language".

Thanks for your help :-)

Answer

skay- picture skay- · Feb 12, 2015

In general your approach will work but a better approach will be to replace:

Child.prototype = new Parent;

with:

Child.prototype = Object.create(Parent.prototype);

This way you don't need to call new Parent, which is somewhat an anti-pattern. You could also define new properties directly as follows:

Child.prototype = Object.create(Parent.prototype, {
  setPosition: {
    value: function() {
      //... etc
    },
    writable: true,
    enumerable: true,
    configurable: true
  }
});

Hope this helps.

Object.create() at MDN