Prototype
Prototype is an object from which other objects inherit properties and the way we can inherent property to the object. You can not define Class in JavaScript. However, we can do a similar thing. How we can create class-ish something and inherent. The answer is Object. Any object has an internal connection between other objects internally, which is called Prototype. Prototype object has own prototype and search property through Prototype. This is called prototype chain. If prototype chain ends, it returns null.
The syntax someObject.[[Prototype]]
referes prototype of someObject which is equal to someObject.__proto__
Here is prototype chain
Cat.__proto__ === Function.prototype
Cat.prototype.__proto__ === Object.prototype
Object.__proto__ === Function.prototype
Function.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ // null => this is end of prototype chain
myCat.__proto__ === Cat.prototype // true
myCat.__proto__.__proto__ === Object.prototype // true
Cat.prototype.__proto__ === Object.prototype // true
How prototypal inheritance works
Here is parent object.
var animal = {
bark: function(bark){
return bark;
},
stop: function(){
return this.bark("Baw");
}
};
It is kind of obsolete technic to make an inherent relationship.
var dog = {};
// Set the object prototype
dog.__proto__ = animal;
console.log(dog.__proto__ === animal); // true
console.log(dog.bark("wao")) //wao
console.log(dog.stop()) //"Baw"
since ES5, it is better syntax.
var dog = Object.create(Animal);
console.log(dog.__proto__ === animal); // true
console.log(dog.bark("wao")) //wao
console.log(dog.stop()) //"Baw"
Object.create
create empty object and add __proto__
on it.
javascript-inheritance-patterns
Prototype Inheritance gives reference to child
Variable assignment is done by passing value. When you refer the property of an object, it is not passed by value which means not copy of the value. It refers to parent property through prototype chain if it can not find property in itself. Deep prototype chain can make program slower so that we have to make sure you don't create too deep to refer unnecessarily.
Ex1:) Pass by Reference
var animal = {
name: "kei"
}
var dog = {}
dog.__proto__ = animal
dog.name // "kei"
animal.name = "John"
dog.name // "John"
Ex2:) Pass by Reference
var e = {
message: "Hello"
}
var f = Object.create(e);
console.log(f.__proto__);
console.log(f.message); // "Hello"
e.message = "Error"
console.log(f.__proto__);
console.log(f.message); // Error
Ex3:) Pass by Value
var a = [1,2,3];
var b = a; // Copied value
console.log(a); //[1,2,3]
console.log(b); //[1,2,3]
a = [4, 5, 6];
console.log(a); //[4,5,6]
console.log(b); //[1,2,3]
Ex4:) Pass by value
var c = {
a: [7,8,9]
}
var d = c.a //copied value [7,8,9]
c.a = [10, 11, 12];
console.log(c.a); //[10, 11, 12]
console.log(d); //[7, 8, 9]
Create inheritance
Creating inheritance consists of 2 steps. Create empty object that has a linkage to parent's prototype and call parent function with child this
context.
function Dog(name) {
Animal.call(this, name);
}
function Animal(name) {
this.name = name;
}
Dog.prototype = Object.create(Animal.prototype);
var dog = new Dog("kei");
// Dog {name: "kei"}
The code is equivalent to...
class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
}
__proto__ and prototype in JavaScript
__proto__
is the actual object that is used in the lookup chain to resolve methods, etc. prototype is the object that is used to build __proto__
when you create an object with new
When creating a function, a property object called prototype is being created automatically and is being attached to the function object. This new prototype object also points to or has an internal-private link to, the native JavaScript Object. If you will create a new object out of Foo using the new keyword, you basically creating (among other things) a new object that has an internal or private link to the function's prototype Foo we discussed earlier
this
in prototype
function Animal(name){
this.animalName = name;
}
function Plant(name){
var plantName = name;
}
var animal = new Animal("Kei");
var plant = new Plant("John");
When we don't bind variable on this
context for Plant, it will be not accessed from an object.
We attached animalName by using this
keyword.
What happened in this case?
function Animal(name){
this.animalName = name;
this.printName = function(){
console.log(this.animalName);
}
}
function Plant(name){
var plantName = name;
this.printName = function(){
console.log(plantName);
}
}
var animal = new Animal("Kei");
var plant = new Plant("John");
console.log(animal.printName());
console.log(plant.printName());
Closure works on Plant constructor function. animal.printName()
access own property animalName
. Plant does not have property plantName
but access value from closure.
function plant(name){
var plantName = name;
this.printName = function(){
console.log(plantName);
}
}
plant("John");
What if we call this plant function as not a constructor but function.
Unless object created from a constructor, this context is global scope in this case so that this context will be the window
.
function Dog(){};
Dog.prototype = {
legs: function(){
},
height: function(){
return this.height;
}
};
var dog = new Dog();
dog.__proto__
// Object {
// legs: function(){
// },
// height: function(){
// return this.height;
// }
// }
dog.__proto__ == Animal.prototype // true
dog
refers to Dog
prototype. The __proto__
getter function exposes the value of the internal [[Prototype]] of an object.
var o = {}
Object.prototype === o.__proto__ //true
o.constructor === Object;
var f = function(){}
Function.prototype === f.__proto__
var Cat = function(name){ this.name = name; }
var myCat = new Cat("Kei");
myCat.prototype
myCat.__proto__ // {}
Cat.prototype = { getName: function(){ return this.name }}
myCat.__proto__
How instance refers to prototype? It is not whole copy of constructor function. Prototype object of constructor is always referred from instance object dynamically through prototype chain.
function Cat(){}
var myCat = Cat("Kei");
myCat.__proto__
// Object >
// constructor: Cat(name)
// __proto__: Object
Cat.prototype.getName = function(){
return this.name;
}
myCat.__proto__
// constructor: Cat(name)
// getName: function()
// __proto__: Object
Constructor property on instance points prototype.constructor
Instance objects does not have constructor property. Prototype of constructor function has constructor. You might have called constructor property on the instance.
function Cat(){}
var cat = new Cat();
Object.prototype.hasOwnProperty.call(cat, "constructor"); // false
Object.prototype.hasOwnProperty.call(cat.__proto__, "constructor"); // true
Why you might want to use prototype method of Built-in Object?
Object.prototype.hasOwnProperty.call()
Array.prototype.slice.call(arguments)
{}.hasOwnProperty
[].slice
{}.hasOwnProperty
and [].slice
call method through prototype chain which takes more time.
ES6 class
ES6 provide class syntax. However, it is just syntax sugar and still Prototype.
super
super keyword allows to go up prototype chain and access to upper object.
class Animal() {
constructor(name) {
this.name = name;
}
}
class Dog() extends Animal {
constructor(name) {
super(name)
}
}