Why does changing the .prototype of a Function affect "instanceof" for objects already created with that constructor function

StackOverflow https://stackoverflow.com/questions/19683444

Question

What I'm attempting to do is create a simple object hierarchy in Javascript where each object in the hierarchy has it's own set of properties, while at the same time be able to use instanceof on those newly created objects. In other words, I wanted my base object (see Person below) to actually contain the firstName and lastName properties. I didn't ultimately want all of my properties to be mashed onto the same "this". I want a nice/neat true Object hierarchy.

To do this, I thought this was the right approach, but it looks like I'm wrong:

var Person = function (firstName, lastName)
{
    this.firstName = firstName;
    this.lastName = lastName;
}

var Ninja = function (beltColor)
{
    this.beltColor = beltColor;
}

Ninja.prototype = new Person ("George", "Clooney");
var ninja1 = new Ninja ("Black");

Ninja.prototype = new Person ("Scarlett", "Johansson");
var ninja2 = new Ninja ("Blue");

Ninja.prototype = new Person ("Brad", "Pitt");
var ninja3 = new Ninja ("Green");

console.log (ninja1 instanceof Ninja); // false
console.log (ninja1 instanceof Person); // true
console.log (ninja2 instanceof Ninja); // false
console.log (ninja2 instanceof Person); // true
console.log (ninja3 instanceof Ninja); // true
console.log (ninja3 instanceof Person); // true

The above code (in my mind) would effectivly create three main objects using the Ninja constructor and the resultant ninja1.__proto__, ninja2.__proto__ and ninja3.__proto__ objects would contain the firstName/lastName properties (which is what I want). These __proto__ objects would also be of "type" Person, being that they were created with the Person constructor and the ninja1, ninja2 and ninja3 objects would be of type "Ninja" (or so I thought), because they were created with the Ninja constructor.

I realize that the reassignment of the Ninja.prototype to a newly created object via the Person constructor is what is throwing of the instanceof operator, but for the life of me, I don't know why.

So I have two questions:

1) Why does the reassignment of the Ninja.prototype to a newly created object via the Person constructor throw off the instanceof operator?
2) What is the correct approach to do what I'm attempting to do? In other words, create a simple object hiearchy where the properties are truly at different levels of the hierarchy, while also being able to use instanceof in a way that makes sense?

Was it helpful?

Solution

Q1: Why does the reassignment of the Ninja.prototype to a newly created object via the Person constructor throw off the instanceof operator?

This does so because the instanceof operator works by going up the prototype chain and checking whether the internal actual prototype of the object ([[Prototype]]) compares with the current prototype property of the constructor function.

Q2: What is the correct approach to do what I'm attempting to do? In other words, create a simple object hierarchy where the properties are truly at different levels of the hierarchy, while also being able to use instanceof in a way that makes sense?

Prototypes are meant for items that are common to all instances of a constructor (for example all people have a brain, but not everyone has the same name). Instead of changing the prototype, add the first name and last name arguments directly as properties of instances of the Ninja function, and make the prototype property of Ninja a blank Person (to cover the case of a person without a name and so that instanceof returns true):

var Person = function (firstName, lastName)
{   this.firstName = firstName;
    this.lastName = lastName;
}

var Ninja = function (beltColor, firstName, lastName)
{   this.beltColor = beltColor;
    Person.call(this, firstName, lastName); // call parent function
}

Ninja.prototype = new Person("", ""); // do this so that instanceof returns true

var ninja1 = new Ninja ("Black", "George", "Clooney");
var ninja2 = new Ninja ("Blue", "Scarlett", "Johansson");
var ninja3 = new Ninja ("Green", "Brad", "Pitt");

console.log (ninja1 instanceof Ninja); // true
console.log (ninja1 instanceof Person); // true
console.log (ninja2 instanceof Ninja); // true
console.log (ninja2 instanceof Person); // true
console.log (ninja3 instanceof Ninja); // true
console.log (ninja3 instanceof Person); // true

OTHER TIPS

The instanceOf method here does not give the constructor of the Ninja object because you have manually assigned the prototype for the NInja object as the "Person" so when traversing through the prototype chain it will have Person object. If you are expecting what you want you can try the below code

var Person = function (firstName, lastName)
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }


var Ninja = function (firstName, lastName, beltcolor)
{
    this.beltColor = beltColor;
    Person.apply(this,arguments);
}

var ninja1 = new Ninja ( "George", "Clooney", "Black");

var ninja2 = new Ninja ("Scarlett", "Johansson","Blue");

var ninja3 = new Ninja ("Brad", "Pitt", "Green");

console.log (ninja1 instanceof Ninja); // true
console.log (ninja1 instanceof Person); // false
console.log (ninja2 instanceof Ninja); // true
console.log (ninja2 instanceof Person); // false
console.log (ninja3 instanceof Ninja); // true
console.log (ninja3 instanceof Person); // false
console.log(ninja1.firstName); //George

Hope this helps you.

You can also look in to below link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain

The instanceof operator looks at the cached prototype chain on the instance and compares it with the constructor you give it. If you've changed the prototype on the constructor, they no longer match.

If you don't change the prototype object completely, and just update properties, that won't happen.

Your object model seems odd; why wouldn't the names be instance properties, just like "belt color"?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top