A few minutes before work, I thoroughly understood the prototype and prototype chain of JavaScript

Posted by manitoon on Wed, 09 Mar 2022 06:29:17 +0100

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_" Property (implicit prototype, which is an object);

3. All functions have a "prototype" attribute (an explicit prototype is an object);

4. "_proto_" for all reference types Attribute points to the "prototype" attribute of its constructor;

5. When accessing the property of an object, if the property does not exist in the object itself, its "_proto_" Property (that is, its prototype).

Note: in JavaScript, everything is an object.

prototype

For a simple example, understand the 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(), * * therefore

Object.__proto__ === Function.prototype

5,Function.prototype is also an object, and there are__ proto__ Property, so get

Function.prototype.__proto__ === Objct.prototype

// Function is also an object and has__ proto__ Property, which is also an object, also has__ proto__ attribute
Function.__proto__.__proto__ === Objct.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   

If you understand it, don't be stingy with your fingers. One key three times in a row~~~

Topics: Javascript Front-end html