Fix for constructor property in protypical inheritence - javascript

The book "JavaScript for Ninja" suggested the following fix for constructor property while establishing prototypical chain between objects:
If I create a Person object as follow:
var person = new Person();
alert(person.constructor == Ninja); // Display true
Even though its fix the problem that ninja.constructor will refer to the Ninja function, But it creates the another problem that now person.constructor will also refer to the Ninja function instead of Person.
Reproducible Example:
function Person() {
}
var person = new Person();
Person.prototype.dance = function() {};
function Ninja() {
}
Ninja.prototype = person;
Object.defineProperty(Ninja.prototype, "constructor", {
enumerable: false,
value: Ninja,
writable: true
})
var ninja = new Ninja();
alert(person.constructor == Ninja); // Display true
I am unable to understand why this fix was suggested by the author.

You're only modifying the constructor property of that one person instance, not the whole Person class. If you do
person2 = new Person();
console.log(person2.constructor == Ninja);
it will print false.
Notice that in the book you quoted, it didn't even assign the new Person() object to a variable, it just created an anonymous object for use in creating the prototype chain.
In general, the object used in the prototype chain will not usually be used as an actual object in the application, it just serves the purpose of linking the related classes.
function Person() {
}
var person = new Person();
Person.prototype.dance = function() {};
function Ninja() {
}
Ninja.prototype = person;
Object.defineProperty(Ninja.prototype, "constructor", {
enumerable: false,
value: Ninja,
writable: true
})
var ninja = new Ninja();
var person2 = new Person();
console.log(person.constructor == Ninja);
console.log(person2.constructor == Ninja);

Related

Javascript prototype chain behaves unexpectedly

Here is my code:
var Person = new Function() // same as function Person(){}
var john = new Person()
now I have prototype chain like that: Object -> Function -> Person -> john
Now I am doing something like that:
Function.prototype.bar = "boo"
So I expect to have Person.bar and john.bar to be "boo"
Person.bar // boo
john.bar // undefined
so what happened? I dived into and found out that john.__proto__ is prototype of Person, but john.__proto__.__proto__ is NOT prototype of Function, it's prototype of Object, so I lost one piece of chain(Finction). that's why john.bar was undefined. So why is this happening? shouldn't I be able to access Function prototype properties from john?
When you have
var Person = new Function()
you get an empty function which does nothing and returns nothing, eg
function Person() {
}
When you create an instance of Person with new, the newly created object will look at Person.prototype, and since Person.prototype inherits from Object (not Function), you won't see the .bar property.
function Person() {
}
const john = new Person();
console.log(
Object.getPrototypeOf(john) === Person.prototype,
Object.getPrototypeOf(Person.prototype) === Object.prototype
);
It's really weird to try to create an instance of a function, but if you wanted to, I suppose you could get what you're looking for by having Person return a Function instance:
Function.prototype.bar = "boo"
function Person() {
return new Function();
};
const john = new Person();
console.log(john.bar);
I'd highly recommend not trying to create Function instances like this, though.
If you want an (odd) inheritance chain of
Object -> Function -> Person -> john
then you can use Object.create:
//const Person = Object.create(Function);
// or
const Person = new Function();
const john = Object.create(Person);
Function.prototype.foo = 'foo';
console.log(john.foo);
Consider the following image taken from this answer.
As you can see, when you create a function in JavaScript a new prototype object is automatically created as well.
function Person() {}
Hence, the above code is actually:
function Person() {}
Person.prototype = { constructor: Person };
Now, you should also understand that the __proto__ property of a function is different from its prototype property.
function Person() {}
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype !== Function.prototype); // true
When you create an instance of Person using the new keyword, that instance object inherits from Person.prototype and not from Person or Person.__proto__:
function Person() {}
const john = new Person;
console.log(john.__proto__ !== Person); // true
console.log(john.__proto__ !== Person.__proto__); // true
console.log(john.__proto__ === Person.prototype); // true
The same goes for functions created by calling new Function.
const Person = new Function;
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype !== Function.prototype); // true
That's the reason why john does not inherit from Function.prototype. The prototype chain for john is as follows.
__proto__ __proto__ __proto__
john -----------> Person.prototype -----------> Object.prototype -----------> null
Whereas the prototype chain of Person is as follows:
__proto__ __proto__ __proto__
Person -----------> Function.prototype -----------> Object.prototype -----------> null
Here's the proof:
const Person = new Function;
const john = new Person;
console.log(john.__proto__ === Person.prototype); // true
console.log(john.__proto__.__proto__ === Object.prototype); // true
console.log(john.__proto__.__proto__.__proto__ === null); // true
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.__proto__.__proto__ === Object.prototype); // true
console.log(Person.__proto__.__proto__.__proto__ === null); // true
This is because Person.prototype !== Person.__proto__.
Now, you may ask why do we have both the prototype and the __proto__ properties. The reason for this is because an object in JavaScript (let's call it derived) inherits from another object (let's call it base) if and only if derived.__proto__ = base. Consider the following code:
const base = { foo: 10 };
const derived = {};
derived.__proto__ = base; // derived now inherits from base
console.log(derived.foo); // 10
const newBase = { bar: 20 };
derived.__proto__ = newBase; // derived no longer inherits from base, it inherits from newBase
console.log(derived.foo); // undefined
console.log(derived.bar); // 20
Now, when you create an instance of a function the instance actually inherits from the prototype of the function. It doesn't inherit from the function.
function Person() {}
const john = new Person;
The above code is equivalent to:
function Person() {}
Person.prototype = { constructor: Person };
const john = { __proto__: Person.prototype };
Person.call(john);
Hope that clears things.

Understanding Javascript Prototype Chains and Inheritance - Example

Could some javascript ninja explain to me why my constructor is botched here? I feel like I'm implementing the prototype chain correctly. I know I could use Object.create, but I'm just interested in understanding why this doesn't work.
var Vehicle = function() {}
Vehicle.prototype.accelerate = function() { console.log('VRRRROOOOOOOM') }
Vehicle.prototype.brake = function() { console.log('SCREEEEECH') }
var Car = function() {}
Car.prototype = new Vehicle
Car.prototype.openTrunk = function() { console.log('POP') }
Car.prototype.closeTrunk = function() { console.log('CLUNK') }
// Test
var mazda = new Car
console.log(mazda) // prototype chain is right
console.log(mazda.constructor === Car) // should be true
console.log(mazda.constructor === Vehicle) // should be false
https://jsfiddle.net/6j43r8qg/1/
The constructor property is defined on the prototype.
Car.prototype = new Vehicle
overrides the prototype and assigns an instance of Vehicle to it. All Vehicle instances inherit constructor, which points to Vehicle, from Vehicle.prototype.
Also I think instanceof would be the way to check if something is a something
console.log(mazda) // prototype chain is right
console.log(mazda instanceof Car) // should be true
console.log(mazda instanceof Vehicle) // should be *true?!*

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

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?
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
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"?

A case where javascript prototype property is undefined. Would like to find out the reason

var Person = function(name){
this.name = name;
};
console.log("1 " + typeof(Person.prototype)) //"object" - prototype is a property of a first class functional object
Person.prototype.sayhi = function(){console.log("hi")};
var john = new Person();
console.log("2 "+typeof(Person.sayhi)) // "undefined"
console.log("3 "+typeof(john.sayhi))// "function"
I am trying to get a better understanding of javascript prototype.
I wonder why case 2 returns undefined, while case 3 returns "object" as it should.
I read up on other posts but can't seem to find the answer. Thanks.
Functions attached to the prototype (Person.prototype) are not accessible from a constructor (Person), that is Person.sayhi is not trying to access the prototype at all.
When you call a constructor (say var p = new Person()), Person.prototype is attached to the prototype chain of the created object (p), that's why you can call p.sayhi(). However, sayhi is never attached to the constructor
Because your "2" console.log isn't looking at the prototype:
Person.sayHi = function() { console.log('I am not in an instance'); }
console.log(typeof(Person.sayHi)); //"function"
var john = new Person();
console.log(typeof(john.sayHi)); //"undefined"
is different than:
Person.prototype.sayHi = function() { console.log('Hi'); }
console.log(typeof(Person.sayHi)); //"undefined"
console.log(typeof(Person.prototype.sayHi)); //"function"
var john = new Person();
console.log(typeof(john.sayHi)); //"function"
sort of the difference between static and instance methods in c#/java

Question regarding Inheritance in JavaScript

Can you please explain the difference between two codes mentioned below ?
function Person(){}
Person.prototype.dance = function(){};
function Ninja(){}
Ninja.prototype = Person.prototype;
and
function Person(){}
Person.prototype.dance = function(){};
function Ninja(){}
Ninja.prototype = new Person();
I am little confused at these lines:
Ninja.prototype = Person.prototype;
and
Ninja.prototype = new Person();
I came to know the second one supports Inheritance and the first one not, Can you explain me what is the magic in the second one?
Setting Ninja.prototype = Person.prototype; is saying that all Ninjas are Persons, and all Persons are Ninjas, since it simply makes the two prototypes point to the same thing. So changing Ninja.prototype will change Person.prototype and vice versa.
Setting Ninja.prototype = new Person(); is saying that all Ninjas start off being a regular person, but Ninja.prototype can be modified without changing the definition of Person. The key here is the new keyword, which creates a unique instance of Person, and is therefore free to be modified without affecting anything else.
Example of Ninja.prototype = Person.prototype
Define Ninja's prototype to be the same as Person's:
function Person() {}
Person.prototype.dance = function () {}; // A Person can dance
function Ninja()
Ninja.prototype = Person.prototype; // Now a Ninja can dance too!
An instance of Ninja has the abilities of Person:
var ninja = new Ninja();
ninja.dance();
But, modifications to the definition of Ninja also affect instances of Person:
Ninja.prototype.kill = function () {}; // Oh no! Now a Person can kill too!
var bob = new Person();
bob.kill(); // Not what we wanted...
Example of Ninja.prototype = new Person()
Define Person in the same way as before:
function Person(){};
Person.prototype.dance = function () {}; // A Person can dance
Now I'll break Ninja.prototype = new Person() into two steps. First, create a new Person, called defaultNinja:
var defaultNinja = new Person(); // Despite the name, it's just a regular Person
Then define all Ninjas to be like the default:
function Ninja(){};
Ninja.prototype = defaultNinja; // Really the same as Ninja.prototype = new Person();
This time if we change what Ninjas can do:
Ninja.prototype.kill = function () {};
// OR,
defaultNinja.kill = function () {};
Instances of Person aren't affected:
ninja.kill(); // Now the ninja can kill
var bob = new Person();
bob.kill(); // ERROR, because Person.prototype doesn't have kill(),
// only defaultNinja does

Categories