preface
JavaScript prototype and prototype chain have always been the focus and difficulty of interview, which is not so easy to understand.
text
Understanding several key points of prototype makes it easier to understand the concept of prototype:
1. All reference types (arrays, objects, functions) can freely extend attributes (except null);
2. All reference types have a "proto" attribute (an implicit prototype is an object);
3. All functions have a "prototype" attribute (an explicit prototype is an object);
4. The "proto" attribute of all reference types points to the "prototype" attribute of its constructor;
5. When accessing the attribute of an object, if the object itself does not have the attribute, it will look for it in its "proto" attribute (that is, its prototype).
Note: in JavaScript, everything is an object.
prototype
// Define a constructor function Fn(name,age){ this.name = name; this.age = age; } /* As can be seen from point 3 above, all functions have a prototype attribute, which is an ordinary object From point 1 above, all objects can freely extend attributes (except null) through prototype */ Fn.prototype = { // There are other properties in the prototype object showName: function(){ console.log("My name is " + this.name); }, showAge: function(){ console.log("I'm " + this.age + " years old"); } } let obj = new Fn('leo',18) /* When accessing the property of an object, if the property does not exist in the object itself, Then it will go to the prototype attribute of its constructor */ obj.showName(); // My name is leo obj.showAge(); // I'm 18 years old
This is the prototype. It's easy to understand. So why use prototypes?
Imagine if we want to create multiple objects through Fn()
function Fn(name,age){ this.name =name; this.age = age; this.showName = function(){ console.log("My name is " + this.name); }, this.showAge = function(){ console.log("I'm " + this.age + " years old"); } }
Then every object we create will contain showName and showAge methods, which will occupy a lot of resources. If it is implemented through the prototype, you only need to assign a value to the prototype attribute in the constructor and write the extended method in FN In the prototype attribute, so that each object constructed through this constructor can use the showName and showAge methods in the prototype attribute, which saves a lot of resources.
Prototype chain
If you understand the prototype, the prototype chain will be well understood.
It can be seen from point 5 that when accessing the attribute of an object, if the object itself does not have this attribute, it will look for it in the "prototype" attribute (i.e. prototype) of its constructor. Because the "prototype" attribute is also an object, it also has a "_ proto_" attribute
// Define a constructor function Foo(name,age){ this.name = name; this.age = age; } Object.prototype.toString = function(){ console.log("My name is " + this.name + " And I'm " + this.age + " years old"); } let fn = new Foo('leo',18); fn.toString(); // My name id leo And I'm 18 years old console.log(fn.__proto__ === Foo.prototype); // true console.log(Foo.prototype.__proto__ === Object.prototype); // true console.log(fn.toString === Foo.prototype.__proto__.toString); // true // Prototype chain mechanism (looking up layer by layer), FN ToString actually accesses object prototype. toString console.log(fn.toString === Object.prototype.toString); // true console.log(Object.prototype.__proto__ === null); // true
From the above example, the following figure is obtained (image source network)
1. The constructor of fn instance is Foo(), so
fn.__ proto__ === Foo.prototype
2,Foo.prototype is also an object (with the proto attribute), and its constructor is Object(), so
Foo.prototype.__proto__ === Object.prototype
3. toString() is in object In prototype, when the method does not exist in the called object itself, it will look up layer by layer until it is null.
4. When fn calls toString(), it is found that fn itself does not have this method, so it goes to foo Find it in the prototype, find it or not, and then continue to object Find it in the prototype. If it is found, call object toString() method in prototype.
This is the prototype chain, fn which can call object The method in prototype is precisely because of the mechanism of prototype chain.
Note: when using a prototype, it is generally recommended to write the method to be extended in the prototype attribute of the constructor.
After understanding the above example, let's take a look at the following figure (image source network)
Combined with the above example for analysis
fn: custom objects
Foo: custom function
1. Custom function (new) - > custom object
let fn = new Foo('leo',18);
2. Custom object (proto) – > custom function prototype
fn.__ proto__ === Foo.prototype
3. In Js, everything is an object, and user-defined functions are no exception, that is, they also exist__ proto__ Property, and the constructor of the custom function is Function(), so
Foo.__proto__ === Function.prototype
4. The constructor of Object() is also Function(), so
Object.__proto__ === Function.prototype
5,Function.prototype is also an object, and there are__ proto__ Property, so get
Function.prototype.__proto__ === Object.prototype // Function is also an object and has__ proto__ Property, which is also an object, also has__ proto__ attribute Function.__proto__.__proto__ === Object.prototype
6,Object.prototype is also an object, and there are__ proto__ Property, the difference is
// Object.prototype is the top layer, and its__ proto__ null Object.prototype.__proto__ === null