1

I am reading kangax's blog on How ECMAScript 5 still does not allow to subclass an array. Here he is using a different approach of subclassing than the normal prototypal construct

BaseClass.prototype = new Superclass();

What he is doing is this :

function clone(obj) {
  function F() { }
  F.prototype = obj;
  return new F();
}

and then set-up inheritance like this:

function Child() { }
Child.prototype = clone(Parent.prototype);

Can someone explain this two part approach of inheritance and what benefits it gives over the simple one liner approach above?

Edit: I understand from the comments that there is now a standard Object.create() that basically solves the same purpose as clone() method but how does this implementation of clone() work ?

Geek
  • 26,489
  • 43
  • 149
  • 227
  • 1
    Because doing `new Superclass()` may trigger undesired side effects. The `clone` gives you an object that inherits from the parent, but without having to invoke the constructor function. And FYI, there's now a standard method in JavaScript that does this. It's `Object.create()` –  Jul 13 '13 at 09:12
  • The `clone` function in your example has the same purpose as `Object.create`, that's why the answers to the linked question will (hopefully) help you as well. – Felix Kling Jul 13 '13 at 09:13
  • @CrazyTrain What *sideeffects* can happen if `new Superclass()` is invoked? – Geek Jul 13 '13 at 09:25
  • @FelixKling PLease see the edit and +1 for your link to the previous answer of yours. It definitely helped. But this question is now more about the implementation of `clone()`. – Geek Jul 13 '13 at 09:31
  • @Geek A great share of FelixKing's answer also applies to this situation. – user123444555621 Jul 13 '13 at 09:47
  • 1
    You have an empty constructor function `F` and set the prototype object of `F` to the value you pass as argument to `clone`. That means every *instance* of `F` is an "empty" object that inherits from `obj`. That's exactly what `Object.create` does. It creates a new object that inherits from the argument. – Felix Kling Jul 13 '13 at 10:17
  • 1
    @Geek: For example if the constructor requires an argument, and performs specific operations on it. When you're setting up inheritance, you may not have a value to pass it. Or maybe the constructor adds properties to the object that shouldn't be inherited. Basically anything that you could put in the constructor that you *wouldn't* want to run when making your object for `Child.prototype`. –  Jul 13 '13 at 13:19

2 Answers2

0

That's an interesting question. The piece of code you're giving (clone function) was called "prototypal inheritance" by Douglas Crockford, and described in this article on his website. This pattern became popular and was formalized in ECMA script 5 into Object.create(), if you look at specification of object create, it is exactly the same as the specification of Crockford's function. It is used like this:

var Animal = {
    species: "mammal",
    noises: function () {
        console.log("makes noises")
    },
    actions: ["roll back", "jump up"]
}

var Cat = Object.create(Animal);
Cat.name = "blacky"
Cat.miau = function () {
    console.log("miau miau");
}

Crockford also calls this differential inheritance, because when defining new properties of subclass you simply specify differences between subclass and superclass. Cat now has its own property "name" and its own method "miau".

I believe the main problem with this is that you still share reference values such as arrays between instances.

If we do:

var Cat2 = Object.create(Animal);
Cat2.actions.push("bite Henry");
Cat2.actions
["roll back", "jump up", "bite Henry"]
Cat.actions
["roll back", "jump up", "bite Henry"]

But at least instance primitive properties are not shared which is fine.

Cat2.name
undefined
Cat.name
"blacky"
Pawel Miech
  • 7,742
  • 4
  • 36
  • 57
0

To demonstrate why you want to use Object.create or a helper function to set prototype for inheritance see the following code:

function Hamster(name){
  if(name ===  undefined){
    throw new Exception("Name cannot be undefined");
  }
  this.name=name;
};

function RussionMini=function(name){
  Hamster.apply(this,arguments);
};
RussionMini.prototype=new Hamster();//throws Error

You can do RussionMini.prototpe=new Hamster("dummyvalue"); but what if a value needs to be passed that isn't available when you declare your object (like a DOM element). You can still pass a dummy but it makes your code more complex and easier to break when refactoring.

Both examples do not repair the prototype.constructor so this.constructor will point to the wrong function (also happens when you use Object.create(Parent.prototype);`

More on inherit, overriding functions and prototype using construction functions can be found here: Prototypical inheritance - writing up

Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160