Prototype and Prototype Chain

Prototype and Prototype Chain

JavaScript has made many attempts to solve reusability, and finally decided to use prototypes and prototype chains to solve them. This is very different from high-level languages ​​such as Java. Java can inherit a certain class through the extended keyword for easy reuse. Before ES6, all data types in JavaScript except for the basic types are objects (reference types), and there are no classes. In order to achieve similar inheritance to reuse code, JavaScript chose prototypes and prototype chains. Even after ES6, JavaScript has no real classes. Although ES6 provides the class keyword so that we can fake a "class", it's actually just syntactic sugar, and it's still an object in essence. The essence of ES6's implementation is still based on prototypes and prototype chains.

1.1 Prototype, prototype, proto

1.1.1 The prototype is an object.

1.1.2 Prototype is only a property of a function, and it is also an object. It has no absolute relationship with the prototype (many books and many internet articles vaguely describe the prototype as the prototype, which is seriously wrong). Functions in JavaScript are also a kind of object. Every object has a prototype, but not all objects have a prototype property. In fact, only functions have this property.

const a = function(){};
const b=[1,2,3];
//Functions have prototype properties
console.log(a.prototype);//>> function(){}
//Non-function, no prototype attribute
console.log(b.prototype);//>> undefined

1.1.3 Each object (instance) has an attribute proto, which points to the prototype attribute of its constructor.

1.1.4 The prototype of an object is the value of the prototype property of its constructor, so _ proto _ is also synonymous with the prototype.

1.1.5 The _ proto of the object also has its own proto, layer by layer until proto _ is null. In other words, the prototype itself has its own prototype. This data structure linked by layers of prototypes becomes a prototype chain. Because null no longer has a prototype, the end of the prototype chain is null.

Let us use more code to verify the above conclusion:

var a = function(){};
var b=[1,2,3];
//a's constructor is "Function function"
console.log(a.__proto__ == Function.prototype);//>> true
//b's constructor is "Array function"
console.log(b.__proto__ == Array.prototype);//>> true
//Because "Function function" and "Array function" are both objects, its constructor
//It is the "Object function", so the prototypes of the prototypes of a and b are both Object.prototype
console.log(a.__proto__.__proto__ === Object.prototype);//>> true
console.log(b.__proto__.__proto__ === Object.prototype);//>> true
//Object as the constructor of the top-level object, the prototype of its instance itself no longer has a prototype, so its prototype
//The __proto__ attribute is null
console.log(new Object().__proto__.__proto__);//>> null
//That is the Object type object, the __proto__ of its prototype (Object.prototype) is null
console.log(Object.prototype.__proto__);//>> null

1.2 Prototype inheritance Use the latest method Object.setPrototypeOf (similar to Reflect.setPrototypeOf) to easily set a prototype for an object, and this object will inherit all the properties and methods of the prototype. However, the performance of setPrototypeOf is very poor, we should try to use Object.create() to set a prototype for an object.

//The prototype of obj is Object.prototype
var obj={
methodA(){
console.log("coffe");
}
}
var newObj = Object.create(obj);//Create a new object with obj as the prototype
//methodA is actually a method on the newObj prototype object obj. That is, newObj inherits the properties and methods of its prototype object obj.
newObj.methodA();//>> coffe

1.3 The search mechanism of the prototype chain When we access a method or property of an object, if there is no such property or method on the object, the JS engine will traverse each prototype object in the prototype chain, and look for the property or method in these prototype objects until it is found. If the entire prototype chain is traversed and still cannot be found, an error will be reported. The code example is as follows:

var obj={
methodA(){
console.log("coffe");
}
}
var newObj = Object.create(obj);//Create a new object with obj as the prototype
newObj.hasOwnProperty("methodA");//>> false

In the above code, the hasOwnProperty method is not defined on newObj, nor is it defined on its prototype obj. It is the method of the prototype Object.prototype on the prototype chain.

Does it feel similar to the "variable search mechanism" on the scope chain? Yes, this is one of the design aesthetics that JavaScript follows: normalization. You can also understand it as consistency and similarity.