7

I'm reading about the mixin pattern in javascript and I encountered this piece of code that I don't understand:

SuperHero.prototype = Object.create( Person.prototype );

There is actually a typo in the original code (the uppercase H). If I downcase it it works. However, if I actually delete the line everything seems to work the same.

Here is the full code:

var Person =  function( firstName , lastName ){
  this.firstName = firstName;
  this.lastName =  lastName;
  this.gender = "male";
};

// a new instance of Person can then easily be created as follows:
var clark = new Person( "Clark" , "Kent" );

// Define a subclass constructor for for "Superhero":
var Superhero = function( firstName, lastName , powers ){

    // Invoke the superclass constructor on the new object
    // then use .call() to invoke the constructor as a method of
    // the object to be initialized.

    Person.call( this, firstName, lastName );

    // Finally, store their powers, a new array of traits not found in a normal "Person"
    this.powers = powers;
};

SuperHero.prototype = Object.create( Person.prototype );
var superman = new Superhero( "Clark" ,"Kent" , ["flight","heat-vision"] );
console.log( superman ); 

// Outputs Person attributes as well as powers

What does SuperHero.prototype = Object.create( Person.prototype ); do?

methodofaction
  • 70,885
  • 21
  • 151
  • 164
  • Realted: http://stackoverflow.com/questions/2449254/what-is-the-instanceof-operator-in-javascript/2449264#2449264 – JonH Sep 11 '12 at 17:52

3 Answers3

4

It creates a new object that inherits from the Person constructor's prototype object.

It would be just like if you did this.

SuperHero.prototype = new Person();

Except that it creates the Person instance without actually invoking the code in the Person constructor.

This object is used as the prototype object of the SuperHero constructor, so that when you create a SuperHero instance, it will inherit all the prototyped properties of Person, as well as any prototyped properties added directly to the SuperHero prototype object.

gray state is coming
  • 2,107
  • 11
  • 20
  • Ahhh, so if there's `Person.prototype.die = function(){...}` I can then do `superhero.die()` ? – methodofaction Sep 11 '12 at 18:02
  • 1
    @Duopixel: Exactly. :) The prototype chain will search in the order of `object -> SuperHero.prototype -> Person.prototype -> Object.prototype -> null;` – gray state is coming Sep 11 '12 at 18:04
  • @graystateiscoming +1 btw - quick question: "without actually invoking the code in the Person constructor". This part is throwing me off, what do you mean by that? – Mark Pieszak - Trilon.io Sep 11 '12 at 18:13
  • 1
    @mcpDESIGNS: In ECMAScript 3, you could only create a custom object by invoking a constructor function. So to create a `Person`, you would need to invoke the `Person` function using `new`, as in `var p = new Person()`. But in ECMAScript 5, we get `Object.create`, which lets us create an object that has the exact same prototype chain as an object made using `new`, except that we didn't need to actually call the `Person` function. This is useful if we want a plain `Person` object without the side effects of the constructor function. – gray state is coming Sep 11 '12 at 18:17
  • Ah very nice, so it doesn't actually "Run" any of the code/functions inside, it simply lets the prototypes be accessed / inherited / whatever. Is there any specific reason its `Object.create( Person.prototype );` not just `Object.create( Person );` as it would be if we used the old `SuperHero.prototype = new Person();` method – Mark Pieszak - Trilon.io Sep 11 '12 at 18:18
  • @mcpDESIGNS: Right. The reason we don't pass a `Person` function as the argument, but instead we pass the prototype object directly is that it opens up the door to create prototype objects that aren't actually part of any constructor function. Say if I have this object `var prot = {foo:"bar"}`, I can can create a bunch of other objects that inherit from this object by doing `Object.create(prot)`. Not a constructor function in sight, yet I still get to use prototypal inheritance. – gray state is coming Sep 11 '12 at 18:21
  • Very cool, looks like I'll have to start trying to use this, as soon as I can stop supporting stupid IE7 haha – Mark Pieszak - Trilon.io Sep 11 '12 at 18:28
  • 2
    @mcpDESIGNS: Use it today! :) http://jsfiddle.net/KAtmJ/ This is a shim that lets you do nearly the same. It doesn't support the second argument to `Object.create`, and doesn't let you use `null` as the prototype object, but it does let you create objects that inherit from a specified prototype. Enjoy! :) – gray state is coming Sep 11 '12 at 18:37
  • Thanks! Weirdly I added that to the top of my JS library with and got `Uncaught SyntaxError: Unexpected token ILLEGAL` error... strange, can't figure out why. – Mark Pieszak - Trilon.io Sep 11 '12 at 19:12
  • @mcpDESIGNS: That happens sometimes when you copy/paste from jsfiddle. There's an invisible invalid character that jsfiddle uses for its code formatting. Often it will appear near the end of the code. If you put your cursor at the end of the code (or some characters past the end), and use your left arrow key to slowly move backward through the characters, at some point, you'll notice that the cursor doesn't move for one single keypress. That's where the invisible character is. You just need to delete it by positioning the cursor alongside it, and hitting delete. – gray state is coming Sep 11 '12 at 19:23
  • ...or just delete all the code you pasted, and retype it manually. :) – gray state is coming Sep 11 '12 at 19:24
  • Yuuup that was it, damn jsfiddle haha – Mark Pieszak - Trilon.io Sep 11 '12 at 19:30
1

It does exactly as the docs state:

Creates a new object with the specified prototype object and properties.

The proto in this case is Person:

The parameter states the following:

The object which should be the prototype of the newly-created object.

Your code Object.create( Person.prototype ); returns an object that copies the properties (in this case the firstName, lastName, and gender) of a person and assigns them to a SuperHero.

Note the similarities between a Person and a SuperHero they both contain a firstName and a lastName. Note also the differences, the Person contains a gender property while your SuperHero contains a powers property.

JonH
  • 32,732
  • 12
  • 87
  • 145
  • `Object.create` doesn't copy any properties. The object created using `Object.create(Person.prototype)` will not have the `firstName`, `lastName`, and `gender` properties that are assigned in the `Person` constructor. – gray state is coming Sep 11 '12 at 18:03
  • But it doesn't really even obtain them... that is unless they are manually copied to the object, which in this case, it is inside the `SuperHero` constructor with `Person.call(this, firstName, lastName);` where the `Person` function will directly assign them. But it's not coming from the `Object.create(Person.prototype)`, because those properties are not prototyped. – gray state is coming Sep 11 '12 at 18:13
  • @graystateiscoming they inherit those properties. – JonH Sep 11 '12 at 18:14
  • Nope, the properties are not inherited. They are assigned directly to the object because of the `Person.call(this...)` invocation. – gray state is coming Sep 11 '12 at 18:18
1
SuperHero.prototype = Object.create( Person.prototype );

This is basically letting SuperHero inherit all of the properties/prototypes of Person. It is almost the same as using new, but in the new ECMAScript 5 *Object.create()` way. This could also be written like so, if it helps understand it any more.

SuperHero.prototype = new Person();

I don't like linking the prototypes specifically, because it means the two prototypes are intertwined, and I prefer to have one be the SubClass, one the SuperClass.

A good way to see them yourself is do something like this. Here you can really see the inheritance that SuperHero is getting from Person. Notice it has all of the properties (first/last/etc), and it's additional Powers.

jsFiddle demo

var person = new Person();
SuperHero.prototype = person; // inheritance here
// the Object.create way is ECMAScript 5 (which not all browsers support yet sadly)

var superman = new SuperHero( "Clark" ,"Kent" , ["flight","heat-vision"] );
console.log( person );
console.log( superman ); ​
Mark Pieszak - Trilon.io
  • 61,391
  • 14
  • 82
  • 96