4

Currently I implement inheritance in my JavaScript libraries as follows:

parent = function() { };
parent.prototype.hello = function() { alert('parent'); };

child = function() { };
child.prototype = parent.prototype;

However, I've noticed when I override a function in a child "class's" prototype, it undesirably overrides the parent's prototype as well:

child.prototype.hello = function() { alert('child'); }

(new parent()).hello();  // alerts "child" --> undesirable
(new child()).hello();   // alerts "child" --> desirable

And if I delete something from the child's prototype

delete child.prototype.hello;

then the parent's prototype is undesirably affected. So, maybe

child.prototype = parent.prototype;

is not the best way of implementing inheritance? Instead of making child "classes" reference the parent prototype, perhaps it would make more sense to copy the parent prototype to the child prototype?

_.extend(child.prototype, parent.prototype);
Chad Johnson
  • 21,215
  • 34
  • 109
  • 207
  • 1
    yes. you right. it's not nice when children mess up with parents. proper extending is the way to go. – Igor Milla Nov 17 '14 at 17:22
  • 4
    I have yet to see any case where `child.prototype = parent.prototype;` is correct. You probably want `child.prototype = Object.create(parent.prototype);` – apsillers Nov 17 '14 at 17:22
  • 3
    Use `Object.create`. See [Benefits of using `Object.create` for inheritance](http://stackoverflow.com/q/17392857/218196) and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript#Inheritance – Felix Kling Nov 17 '14 at 17:22
  • possible duplicate of [Why wouldn't I use Child.prototype = Parent.Prototype rather than Child.prototype = new Parent(); for Javascript inheritance?](http://stackoverflow.com/q/11088365/1048572) – Bergi Nov 17 '14 at 17:48
  • It's not the same question. They are asking whether to create a new instance of the parent object as the child's prototype, while I am asking whether to copy the parent's prototype. – Chad Johnson Nov 17 '14 at 17:52
  • Common patterns for constructor functions, prototype, inheritance and mix ins are explained here: http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Nov 17 '14 at 23:30

1 Answers1

10

child.prototype = parent.prototype; is incorrect, for the reason you've detailed in your question.

Using _.extend isn't want you want, either. Consider that a change in an "inherited" parent prototype property will not cause a change in the child:

// perform extension
_.extend(child.prototype, parent.prototype);

// parent later gains new property after extension
parent.prototype.parentProp = function() { alert("new"); };

(new parent()).parentProp();  // alerts "new" --> desirable
(new child()).parentProp();   // error; doesn't exist --> undesirable

You probably want child.prototype = Object.create(parent.prototype); This says: "Store a new object in child.prototype. This new object uses the parent.prototype object as its own prototype." This causes real inheritance to happen, because when a child instance wants a property, it first looks in its own properties, then in its immediate prototype (child.prototype), and then in its prototype's prototype (parent.prototype).

Prototype chains

  • When using child.prototype = parent.prototype, the prototype chains for the instances look like:

    { child instance } ==> { only prototype }
    
    { parent instance } ==> { only prototype }
    

    where only prototype is the shared object referred to by both child.prototype and parent.prototype.

  • When using _.extend(child.prototype, parent.prototype), the child prototype and parent prototypes are different, but there's no direct inheritance. Changing the parent prototype doesn't change the child at all, since we merely copied the parent prototype's properties into the child prototype at one single point in time.

    { child instance } ==> { child.prototype }
    
    { parent instance } ==> { parent.prototype }
    
  • With child.prototype = Object.create(parent.prototype); you actually have inheritance happening from parent to child prototype:

    { child instance } ==> { child.prototype } ==> { parent.prototype }
    
    { parent instance } ==> { parent.prototype }
    
apsillers
  • 112,806
  • 17
  • 235
  • 239