javascriptoopinheritanceprototypeextend

Extending prototypes in Javascript - good way?


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:

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 literal 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".


Solution

  • 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