Confused about JavaScript prototypal inheritance - javascript

In the book "JavaScript the definitive guide 5 edition", section 9.2 Prototypes and Inheritance, I find the following words:
In the previous section, I showed that
the new operator creates a new, empty
object and then invokes a constructor
function as a method of that object.
This is not the complete story,
however. After creating the empty
object, new sets the prototype of that
object. The prototype of an object is
the value of the prototype property of
its constructor function. All
functions have a prototype property
that is automatically created and
initialized when the function is
defined. The initial value of the
prototype property is an object with a
single property. This property is
named constructor and refers back to
the constructor function with which
the prototype is associated. (You
may recall the constructor property
from Chapter 7 ; this is why every
object has a constructor property.)
Any properties you add to this
prototype object will appear to be
properties of objects initialized by
the constructor.
Now, if that is true, how could prototypal inheritance exists? I mean, let's say the prototype object of a constructor function has a constructor property initially. Because the prototype object itself is an object, to determine its constructor we often use prototype_object.constructor. But now the prototype_object already has a constructor property itself, and it points to the constructor function with which the prototype is associated. In this situation how can inheritance exists?

The .constructor property honestly doesn't matter very much, and has very little to do with inheriting from other objects in JavaScript. It's just a convenient handle to an object's constructor.
For example, if you have an instance of something, and you'd like to create another instance of that thing, but you don't have a direct handle on its constructor, you could do something like this:
const myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]
const car2 = new myCar.constructor();
console.log(car2.constructor); // [Function: Racecar]
It's important to understand that the .constructor property and the class of an object are not synonymous. As you may have already guessed, the .constructor property is dynamic, just like most other things in JavaScript, so it should not be used for anything like type checking.
It's also important to understand that the .constructor property does not mean that something is a subclass of something else. In fact, there is no reliable way to find out if something is a subclass of something else in JavaScript. Because it's a dynamic language, and because there are so many ways to inherit properties from other objects (including copying properties from other objects after instantiation), type-safe subclasses don't exist in JavaScript like they exist in other languages.
The best way to know if something is a compatible type is to feature-test properties. In other words, duck type.
The instanceof operator ignores the .constructor property. Instead, it checks whether or not the constructor's .prototype exists (with an identity check) in the prototype chain of the object.
With manual constructor functions, inheritance can confuse the .constructor property connection (making it refer to the wrong constructor). You can fix it by manually wiring up the connection. For example, the canonical way to do so in ES5 is this:
function Car () {}
console.log(Car.prototype.constructor); // Car
function Racecar () {}
Racecar.prototype = Object.create(Car.prototype);
// To preserve the same relationship we have with the Car
// constructor, we'll need to reassign the .prototype.constructor:
Racecar.prototype.constructor = Racecar;
var myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]
ES6 classes do this for you automatically:
// ES6
class Car {}
class Racecar extends Car {}
const myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]
That said, I'm not a big fan of either constructor functions or ES6 classes, and I generally have little use for the .constructor property. Why? Because factory functions are far more flexible, far more powerful, and they don't have the pitfalls related to constructor functions and class inheritance. See "Factory Functions vs Constructor Functions vs Classes".

Let say, Dog is a Mammal.
function Mammal() {
this.milk = true;
};
function Dog() {
this.bark = true;
}
Dog.prototype = new Mammal;
So prototype of Dog points to an object of Mammal. This Mammal object has a reference to its constructor so when Dog is new, JavaScript see that Dog prototype is a Mammal so Mammal's constructor is called to produce a valid Mammal object (another one) then make it a Dog object using Dog constructor.
From this, the constructor of Dog.prototype is a Mammal (a Mammal Object that has extra fields and functions added) BUT constructor of Dog is Dog. The inheritance exist because the an instance of Dog has a Mammal as a prototype; hence, Dog is a Mammal. When a method is called and JS cannot find it from Dog.prototype, JS look in Mammal.prototype (which is an Object that has extra fields and functions added).
Hope this helps.

Don't worry about the constructor property - it is irrelevant.
Skip those sentences and you might follow it better.
If you are still unsure of your understanding, google for __proto__ - the internal prototype reference on JS objects. It is even exposed to scripts on Firefox and Safari.
A good reference is https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/The_Employee_Example/Object_Properties/Inheriting_Properties

If you have an object obj, it's prototype is obj.prototype and constructor property referring to obj's constructor is obj.prototype.constructor.
For the object obj.prototype the situation is the same. Let's say proto = obj.prototype, then the reference to the constructor of proto would be found at proto.prototype.constructor.
This is the same as obj.prototype.prototype.constructor, so there is no conflict with obj.prototype.constructor.

Related

Why constructor function prototype can be assigned to an object and what it means

I am reading through the official docs:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
and in the chapter Different ways to create objects and the resulting prototype chain -> With a constructor they have the following:
function Graph() {
this.vertices = [];
this.edges = [];
}
Graph.prototype = {
addVertex: function(v) {
this.vertices.push(v);
}
};
var g = new Graph();
// g is an object with own properties 'vertices' and 'edges'.
// g.[[Prototype]] is the value of Graph.prototype when new Graph() is executed.
But right before that it is written that:
// Functions inherit from Function.prototype
// (which has methods call, bind, etc.)
// f ---> Function.prototype ---> Object.prototype ---> null
So, Graph is a function and it should have Graph.prototype, in my understanding, to be of type Function.prototype and NOT Object.prototype, otherwise Graph would stop being a function and would instead become an object, or so I would think.
Could anyone explain why the prototype of Graph is assigned to an object and why the specified behavior of inheriting then addVertex becomes possible? Would we lose all of the function properties (call, bind) when such assignment happens?
There are two different prototype chains at play:
The prototype chain of the constructor
The prototype chain of objects that are created by that constructor
They have nothing to do with each other. The first is a function and thus related to Function.prototype, the other is not a function, but an object whose prototype object is created at the same time as the constructor function object was created. That prototype object will be used when a new instance is created by calling the constructor with new.
What can be confusing here, is that the constructor has a property that is called prototype, but that is not the prototype object of the constructor (point 1), but of objects it can create (point 2). Possibly this property would have been better named prototypeForConstructedInstances... but that's a bit long ;-)
To get the constructors own prototype you would write Object.getPrototypeOf(constructor),... and you'll see it is Function.prototype.
You may have an interest in reading more about the broader subject of prototypes at "How does JavaScript .prototype work?". It's an interesting read, and you'll also find my answer over there.

Can instances of a constructor inherit members that are not defined within the prototype bucket?

MDN explains that the instances of a constructor only inherit members within the constructor.prototype property, but not anything outside of it. For example, Object.prototype.watch() will be inherited to its instance, but not Object.keys();.
If I have a constructor as follows:
function Person(name) {
this.name = name;
}
Person.prototype.greeting = function() {
alert("Hi!");
}
the name property is not inside the prototype property, but the greeting() method is. However, if I create an instance as such:
let person1 = new Person("Foo");
person1 is able to access person1.name as well as person1.greeting() both even though the name property is defined outside of the prototype property.
Technically the answer is yes: an instance can inherit from the prototype object property of its constructor, as well as any properties that the prototype object inherits. This is the generalized meaning of the "prototype chain".
In the case of the example given however, the confusion arises in believing name is inherited - it is not.
Objects can have local or "own" properties in addition to inheriting properties from their prototype chain. Ignoring more advanced usage of getters and setters, inherited properties are read only: if you write to them the value written is held in an "own" property created to locally hold the value written - meaning the value written shadows the inherited value without overwriting it in place.
For more information please research how JavaScript inheritance works and in particular what the Object.prototype.hasOwnProperty method does.
The property and name and method greeting both are available to the person1 in different ways.
name is available to person1 because of new operator
greeting is available to person1 because of prototype
When new operator is used it always returns a Object. And object have its own properties. name is the property of Object.

Prototypical inheritance without creating a parent object

So I was reading the book Head First Javascript Programming, which is a great book btw, learned me a lot, when I stumbled into the subject of multiple inheritance.
The book taught me that to achieve multiple inheritance you should set the prototype of your constructor to a new object of your parent.
As an example:
//Parent
function Dog (name){
this.name = name;
};
//Child
function AwesomeDog(name){
Dog.call(this, name);
};
AwesomeDog.prototype = new Dog();
AwesomeDog.prototype.constructor = AwesomeDog;
AwesomeDog.prototype.isAwesome = true;
Now I don't agree that this is the best way to do it, you call the Dog constructor only for its prototype property, but you also get the name property with it, that you will typically never use and therefore always be undefined.
Why not just do this:
AwesomeDog.prototype = Dog.prototype;
You're only interested in the prototype anyway so why not?
In my opinion this is better because of 2 reasons:
The overhead of creating a new object is left out (insignificant, but it's something)
You don't have useless properties floating around in your child's prototype, that will probably always remain undefined.
Now this book has been brilliant in every way so that led me to believe that I perhaps missed something crucial, but I can not see what. I can not imagine any use cases where having double properties (one in the child object and the undefined version in your prototype) can be useful.
Is my way of thinking correct and can I stick with my method?
Object inheritance in JavaScript is also the basis of constructor inheritance.
Every function has a prototype property that can be modified or replaced. That prototype property is automatically assigned to be a new generic object that inherits from Object.prototype and has a single own property called constructor. In effect, the JavaScript engine does the following for you:
// you write this
function YourConstructor() {
// initialization
}
// JavaScript engine does this for you behind the scenes
YourConstructor.prototype = Object.create(Object.prototype, {
constructor: {
configurable: true,
enumerable: true,
value: YourConstructor
writable: true
}
});
So without doing anything extra, this code sets the constructor’s
prototype property to an object that inherits from Object.prototype,
which means any instances of YourConstructor also inherit from Object
.prototype. YourConstructor is a subtype of Object, and Object is a supertype
of YourConstructor.
Now I don't agree that this is the best way to do it, you call the Dog
constructor only for its prototype property, but you also get the name
property with it, that you will typically never use and therefore
always be undefined.
You are completely right. Using new has these problems, and thus is discouraged.
Why not just do this:
AwesomeDog.prototype = Dog.prototype;
This has a problem: both AwesomeDog and Dog instances share the same prototype. Therefore, they will inherit the same properties and methods, so there is no point in subclassing. And which should the constructor be, AwesomeDog or Dog?
Instead, the proper way is assigning AwesomeDog.prototype to an object which inherits from Dog.prototype, but without calling Dog. You can do this with Object.create:
AwesomeDog.prototype = Object.create(Dog.prototype);
AwesomeDog.prototype.constructor = AwesomeDog;

JavaScript OOP concepts - Properties

On MDN they state the following:
Properties are variables contained in the class; every instance of the
object has those properties. Properties should be set in the prototype
property of the class (function) so that inheritance works correctly.
Looking at the sections I've set to bold I assumed this meant:
myClass.prototype.newProperty = ...
However their example shows the following:
function Person(firstName) {
this.firstName = firstName;
console.log('Person instantiated');
}
var person1 = new Person('Alice');
var person2 = new Person('Bob');
// Show the firstName properties of the objects
console.log('person1 is ' + person1.firstName); // logs "person1 is Alice"
console.log('person2 is ' + person2.firstName); // logs "person2 is Bob"
In their example they're adding the property 'firstName' directly to the class/function using 'this'.
Does this mean:
a) That the function declaration is the prototype? I.e. myClass is the prototype which also has a property prototype which by default is set to Object?
b) That using 'this.' in the function declaration does actually add the property to the myClass.prototype
Edit: Updated title
JavaScript doesn't have classes, stop thinking in classes, because that doesn't work with JavaScript (yes, even with the ES6 class syntax, it's just sugar, there aren't actual classes in JavaScript).
By adding the property to the object's prototype, you ensure that it and any other objects with the same prototype will share this property, this means that they'll all have it, but it also mean that if you change it on one, it will change with all of them. Oops.
The creation of a new object with the new keyword is fairly straightforward:
Create an empty object
Make that object prototype the same prototype as the constructor's
Call the constructor with this as the newly created object.
So adding a property to the prototype of an object will have it shared among all instances of the same constructor, while adding it to this in the constructor will have it only on this specific instance. Because it's set in the constructor, it's safe to assume that all instances will have that variable in them, although it won't be shared with all other instances.
When you call a JavaScript property, the engine will look for it in the following fasion:
Look for the property on the object itself (that's this inside of methods of that object)
If not found, look for the property on the object's prototype
If not found, go up the prototype chain and look for it there
So in your Person example, the lookup chain will look like:
this > Person.prototype > Object.prototype
The constructor's will look like this:
this > Person.prototype > Function.prototype > Object.prototype
Person is a function, so its prototype is inherited from Function.prototype, similarly any function is an Object.
So to your specific questions:
The function declaration is not the prototype. See the object creation process above.
No, this applies the property on this instance, while prototype is shared among all instances.

Using the Prototype and Constructor Properties of JS in conjunction

From what i understand,a Prototype object is an object from which other objects inherit properties and methods,and basically it holds a Constructor Property that Refers to or points to the Constructor function that created the Object.Please Consider the Following Code:
function Animal()
{
this.name="no name";
}
function Cat()
{
Animal.Call(this); //Please Explain
this.mood="sleepy";
}
Cat.prototype=new Animal(); //Cat inheriting Animal?
Cat.prototype.constructor=Cat; //Please Explain
Please explain clearly but in details the code lines with comments and the concept of reflection,thanks.
what's the Purpose of Animal.call(this)
It's like calling super() in other programming languages. It calls the parent constructor (Animal) on the just created new object (this). This is also explained in the MDN documentation about .call.
In your example, Animal assigns "no name" to this.name. So after calling Animal.call(this);, this will have a name property with the aforementioned value.
and Cat.prototype.constructor=Cat;
By default, each prototype's constructor property points to the function it belongs to. But since you overwriting the prototype with Cat.prototype=new Animal();, the constructor property points to a different function now. In this case, since new Animal returns an object that inherits from Animal.prototype, Cat.prototype.constructor will point to Animal. To fix that, we assign Cat again.
Strictly speaking this is not necessary since the constructor property is not used in any internal function. However, if your code relies on it, it has to be set to the correct value.

Categories

Resources