Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

For inheritance with JavaScript, is it better to reference or copy the parent's prototype?

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);
like image 662
Chad Johnson Avatar asked Dec 26 '22 02:12

Chad Johnson


1 Answers

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 }
    
like image 107
apsillers Avatar answered Dec 28 '22 05:12

apsillers