Search code examples
javascriptinheritanceprototypal

Is this a flaw in JavaScript's prototypical inheritance model?


I've been learning prototypical inheritance in JavaScript from John Resig's Secrets of the JavaScript Ninja, and I was wondering what happens in the following code example (that I just made up).

function Person() {}

Person.prototype.sayHello = function() {
    alert("Hello World");
}

function Ninja() {}

Ninja.prototype.swingSword = function() {
    alert("I can swing my sword.");
}

Ninja.prototype = new Person();

var ninja1 = new Ninja();

As far as I know, the result of all of these lines of code is that the variable ninja1 references a Ninja object, that through its prototype, has the swingSword method, and through prototypical inheritance of Person's prototype, has the sayHello method.

Where I am confused is in the following: since the property swingSword (which happens to be a method) was attached to Ninja's prototype before a person instance was assigned to Ninja's prototype, wouldn't the swingSword property/method be overwritten by the later assignment of the Person instance? If not, how can Ninja's prototype property, which references the prototype object, reference both the Person instance, and have a swingSword property?


Solution

  • [...] that through its prototype, has the swingSword method, [...]

    While the rest of that statement is correct -- that ninja1 references Ninja (well, technically, Ninja.prototype) and will have a sayHello through inheritance -- your later thoughts are correct regarding swingSword.

    wouldn't the swingSword property/method be overwritten by the later assignment of the Person instance?

    At the end of your snippet, ninja1.swingSword should be undefined.

    console.log(typeof ninja1.swingSword); // 'undefined'
    
    // as is:
    console.log(typeof Ninja.prototype.swingSword); // 'undefined'
    

    After Ninja.prototype = ..., the original prototype object that swingSword was attached to is no longer being referenced. So, it won't be used when creating new instances.


    If you intend to set a new prototype object, you'll want make sure that's done before modifying it.

    Ninja.prototype = new Person();
    
    Ninja.prototype.swingSword = function() {
        alert("I can swing my sword.");
    }
    
    var ninja1 = new Ninja();
    
    console.log(typeof ninja1.swingSword); // 'function'
    

    And, if ninja1 actually does have a swingSword, it probably means that it was created before the prototype was changed.

    Objects retain their own [[Prototype]] reference from when they were created regardless of what changes may be made to their constructor's prototype property.

    Ninja.prototype.swingSword = function() {
        alert("I can swing my sword.");
    }
    
    var ninja1 = new Ninja();
    
    Ninja.prototype = new Person(); // won't affect existing instances
    
    var ninja2 = new Ninja();
    
    console.log(typeof ninja1.swingSword); // function
    console.log(typeof ninja2.swingSword); // undefined
    

    Example of each: http://jsfiddle.net/G8uTk/