Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use Object.create for prototype when extending an object?

I have a Java background and I have been experimenting with JavaScript inheritance lately. I started writing some objects and after reading some examples I found the code style which suits me the most.

Here is what I have:

var Class = function() {};
Class.extend = function(p_constructor) {
    var Superclass = this;
    // the following line confuses me
    p_constructor.prototype = Object.create(Superclass.prototype);
    p_constructor.prototype.constructor = p_constructor;
    p_constructor.extend = Superclass.extend;
    return p_constructor;
};

So now when I wish to define an object which extends Class I just type:

var Person = Class.extend(function(p_firstName, p_lastName) {
    this.firstName = p_firstName;
    this.lastName = p_lastName;
});

and the following will be true:

var p = new Person('john', 'smith');
p instanceof Person; // true
p instanceof Class; // true

I only have trouble understanding what's the effective difference between the following lines in the Class.extend function:

/* 1) */ p_constructor.prototype = new Superclass();
/* 2) */ p_constructor.prototype = Superclass.prototype;
/* 3) */ p_constructor.prototype = Object.create(Superclass.prototype);
/* 4) */ p_constructor.prototype = Object.create(Superclass);

I do realize that using the 1st line is not very wise if some super constructors throw errors, but what's exactly the difference between lines 2, 3 and 4?

like image 878
jeremija Avatar asked Aug 31 '13 11:08

jeremija


1 Answers

To answer my own question:

/* 1) */ p_constructor.prototype = new Superclass();

Like I said, it's not very wise to use this because it actually creates the whole Superclass object. The whole point of prototypal inheritance is to share the prototype objects so redundant function (and sometimes object) definitions can be avoided.

/* 2) */ p_constructor.prototype = Superclass.prototype;

This would be OK if you could be sure that the constructor's prototype would never be modified by third party. Suppose somebody who uses your class wants to add additional functionality to its prototype. Changing the p_constructor's prototype would directly influence the superclass' prototype and could introduce errors in the superclass' behaviour. So the next line of code is used instead:

/* 3) */ p_constructor.prototype = Object.create(Superclass.prototype);

This creates a new object (instance) whose prototype (actually the __proto__ variable) is set to Superclass' prototype. Any changes to p_constructor.prototype now makes no changes to the Superclass' behaviour.

/* 4) */ p_constructor.prototype = Object.create(Superclass);

The upper line works, but makes no sense because it only sets the prototype to the Superclass' constructor.

Also, the following line was confusing to me as well:

p_constructor.prototype.constructor = p_constructor;

It makes no difference in the p_constructor's behaviour, it only makes the reference to the constructor available in the instantiated object. A neat trick is to add the superclass to the prototype as well:

p_constructor.prototype.superclass = Superclass;

And then the following piece of code would work:

function Constructor(p_params) {
    // call constructor of the superclass
    this.superclass(p_params);
}
like image 178
jeremija Avatar answered Sep 28 '22 09:09

jeremija