Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why do we use `Boy.prototype = new Human;` to simulate inheritance?

i don't get why everyone is using Boy.prototype = new Human; to simulate inheritance. Look, what we want is the function's of A right? we can do that without instantiating a new A (in fact instantiating a new A does give us undesirable results, in the sense that we are actually running the instantiating function which isn't what we want)

So isn't this a better solution?

for (var prop_name in Human.prototype) {
Object.defineProperty(
          Boy.prototype,
          prop_name,
          Object.getOwnPropertyDescriptor(Human.prototype,prop_name)
        );
}

Say we are that particular and want not only the enumerable properties in Human.prototype we could still achieve it by using Object.getOwnPropertyNames and calling it on the prototype chain, which in turn is available to us through Object.getPrototypeOf.

So what exactly is the benefit of doing Boy.prototype = new Human; to simulate inheritance when we have better options available to us?

like image 618
Pacerier Avatar asked Feb 24 '23 05:02

Pacerier


2 Answers

A better option is to create an intermediate to hold the prototype.

function extend(clazz, superclass) {
    var intermediate = function() {};
    intermediate.prototype = superclass.prototype;
    clazz.prototype = new intermediate();
    // Following line is optional, but useful
    clazz.prototype.constructor = clazz;
}

This avoids unnecessary copying, but still means that you don't need to instantiate an object that will do work in its constructor. It also sets up the prototype chain so that you can use instanceof. It also doesn't result in superclass prototype contamination which some inheritance antipatterns can.

For completeness, your subclass should call the superclass constructor in its constructor, which you can do with Superclass.call(this);.

EDIT: Since ES5, you can replace calls to extend with

Subclass.prototype = Object.create(Superclass.prototype);

which does the same thing.

like image 147
kybernetikos Avatar answered Feb 26 '23 19:02

kybernetikos


  • It sets up the prototype chain correctly, meaning that instanceof and isPrototypeOf() will work
  • It's less verbose

There are simple but ugly workarounds to prevent a constructor function from performing its usual initialization when you're just using it to create a prototype object. For example, you could either check the arguments:

function Boy(name) {
    if (arguments.length == 1) {
        this.name = name;
        // Do other initialization
    }
}

... or move the initialization into a separate method that has to be called explicitly:

function Boy(name) {}

Boy.prototype.init = function(name) {
    this.name = name;
    // Do other initialization
}

This has the obvious downside of requiring you to remember to call init() whenever you create a new Boy.

In ECMAScript 5 environments (current versions of most browsers, for example), a better option may be ECMAScript 5's Object.create(), which allows you to create an object which inherits directly from another object and sets up the prototype chain for you. This can be emulated (but only approximately: see Object.defineProperty in ES5?) in non-ES5 environments:

if (!Object.create) {
    Object.create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }; 
}
like image 44
Tim Down Avatar answered Feb 26 '23 19:02

Tim Down