Exploration and detailed explanation of prototype and prototype chain in Javascript

Let's explore the mystery of the prototype chain together!

foreword

Prototype objects and prototype chains are one of the important knowledge points in Javascript, and they are also frequently mentioned by interviewers, especially the "new generation of migrant workers" who are new to Js. When you mention the prototype chain, the following will appear in your mind This picture:

(It doesn’t matter if you don’t understand it now, after reading this article, you can draw it with your eyes closed, let alone understanding)
insert image description here

The prototype chain is easy to say, but it is really not so easy to understand. It is not too difficult to say that it is not too difficult, just understand the above picture, then let's get to know it together!

Before introducing prototypes and prototype chains, let's talk about the relationship between constructors, instance objects, and prototype objects;

object

In Javascript, everything is an object, all objects are essentially created through the new function , and all functions are essentially created through the new Function . But objects are also different, and can be divided into ordinary objects and function objects ; (refer to the figure below)
insert image description here

In fact, the objects created by new Function() are all function objects. The Person, Object, Array, and Foo in the above figure are all created by New Function(), and they belong to function objects;

Other instance objects created by the new function are ordinary objects. In fact, the prototype object is also an instance of a function, so it is also an ordinary object, but there is only one exception. The prototype object Function.prototype is a function object ;

Constructor

In fact, the most common way for us to create objects at the beginning is to use Object or object literals, but these methods have obvious disadvantages. Using the same interface to create many objects will generate a lot of repetitive code. In order to solve this problem, we started to use The factory mode creates objects and mass-produces objects, which is much more convenient;

//工厂模式
function createPerson (name,age,job){
    
    
   var o = new Object()
   o.name = name
   o.age = age
   o.job = job
   o.sayName = function() {
    
    
      alert(this.name)
   }
   return o
}

var person1 = createPerson ("张三"29"前端")
var person2 = createPerson ("李四"30"测试")

The function createPerson() can construct a person object containing all necessary information according to the received parameters. This function can be called an infinite number of times, and each time returns an object containing three properties and one method. Although the factory function solves the problem of creating multiple similar objects, it does not solve the problem of object identification (that is, how to know the type of an object), so the constructor mode appears;

Constructors are also used to create specific types of objects; native constructors like Object and Array on the right side of the above figure will automatically appear in the execution environment at runtime. In addition, we can also customize some constructors to customize Properties and methods of objects, such as Foo and Person on the left side of the figure above;

//构造函数
function Person (name,age,job){
    
    
   this.name = name
   this.age = age
   this.job = job
   this.sayName = function() {
    
    
      alert(this.name)
   }

}

var person1 = new Person ("张三"29"前端")
var person2 = new Person ("李四"30"测试")

In the above example, the Person() function replaces the createPerson() function. The code of the constructor is very similar to the code of the factory function, but there are also the following differences:

  • Created objects not shown
  • Directly assign properties and methods to this object
  • no return statement

In addition to the above differences, the following characteristics of constructors should also be kept in mind:

  • Constructors always start with a capital letter;
  • To create a new instance object of a class, the new operator must be used;
  • The different instance objects created (person1 and person2) have a constructor attribute, and the attribute points to the constructor (Person) that created them; that is: person1.constructor == Person
  • The constructor attribute of an object is initially used to identify the object type, and later it is more reliable to use the instanceof operator to detect;

Creating a custom constructor means that its instance can be identified as a specific type in the future, and this is where the constructor pattern outperforms the factory pattern;

Although the constructor mode is easy to use, it is not without disadvantages. The main problem with using the constructor is that each method must be recreated on each instance. In the above example, both person1 and person2 have a method called sayName(), but the two methods are not instances of the same Function. Don’t forget that functions in js are objects, so every function defined is an instance transformed an object,

It’s okay to instantiate a small number of objects, but if you want to create hundreds of thousands of objects, then the sayName() method will be repeated hundreds of thousands of times. Since hundreds of thousands of instances need the same method, then Can this method be shared, only created once, and all instances can be used, of course, this problem can be solved by using the prototype mode!

prototype object

In JavaScript, whenever an object is defined, it contains some predefined properties. Each function object has a prototype attribute, which points to the prototype object of the function.

Important: Every object has a _ proto _ property, but only function objects have a prototype property

So what is a prototype object?

Please see the optimized code below:

function Person (name,age,job){
    
    
   this.name = name
   this.age = age
   this.job = job
}

Person.prototype.sayName = function() {
    
    
      alert(this.name)
}

var person1 = new Person ("张三"29"前端")
var person2 = new Person ("李四"30"测试")

The purpose of a prototype object is to contain properties and methods that can be shared by all instances of a particular type . In the above code, two different instances of person1 and person2 can access the sayName method;

It can be understood in combination with the following figure:
insert image description hereAs can be seen from the above figure, as long as a function is created, a prototype attribute will be created for the function according to a set of specific rules, and this attribute points to the prototype object of the function;

And its prototype object will automatically obtain a constructor attribute, which is a pointer to the function where the prototype attribute is located ;

Person.prototype.constructor == Person

instance object

In fact, the prototype object also belongs to the instance object, why?

Why does person1 have a constructor attribute? That's because person1 is an instance of Person.
Why does Person.prototype have a constructor attribute? ? Similarly, Person.prototype is also an instance of Person.

Conclusion: the prototype object (Person.prototype) is also an instance of the constructor (Person);

When the constructor is called to create a new instance, the instance object will contain a pointer (internal attribute _proto_), pointing to the prototype object of the constructor;

insert image description here

person1._proto_ == Person.prototype

The most important thing to be clear is: this connection exists between the instance and the prototype object of the constructor, not between the instance and the constructor;

We can call person1.sayName() or person2.sayName(). Although these two instances do not contain this method, we can use _proto_ to find the object properties on the prototype of its constructor; in fact, this is the simplest one prototype chain;

prototype chain

The prototype chain is that when an instance object searches for an attribute, if it cannot be found, it will search along the __proto__ on the prototype associated with the object, and return if it is found. If it cannot be found, it will find the prototype of the prototype until it is found For the prototype of the topmost Object function, the _proto__ of its prototype object has no upper-level prototype that can be pointed to, so its value is null and returns undefind;

Prototype chain is the main method to realize inheritance. Its basic idea is to use prototype to let one reference type inherit the properties and methods of another reference type;
insert image description here
we have already been familiar with the relationship between constructor, prototype and instance, as shown in the figure above, it is estimated that everyone understood;

Some friends may say that I understand the relationship between the Foo function and its instance object, but its relationship with Object and Function is still not clear. In fact, we can draw inferences from one example, and their relationship is inseparable from the knowledge points we summarized above. Next we will explain one by one:

In order to let you understand, I also specially drew a picture myself:

First , there is a prototype attribute inside the function object pointing to its prototype object ; the prototype object has a constructor attribute pointing to its constructor ; the internal attribute _proto_ of the instance object points to the prototype object of the constructor ; that is, as shown in the following figure:

insert image description here

Then , each object has a proto attribute, and the function object also has a __proto__ attribute ; because functions are created through new Function(), it is also equivalent to an instance of the Function function , so the _proto_ of all function objects points to The prototype object of the Function function ; therefore, the _proto_ property of Foo() and Object() points to the prototype object of the Function function; and the Function function is generated by itself through new, so the _proto_ property of the Function function points to its own prototype object ; that is, as shown in the figure below:

insert image description here
Finally , we all know that everything is an object, and all objects are instances of Object() , and the prototype of the Foo function and the prototype of the Function function belong to the object, in the final analysis, they are all generated by the new Object function, so their _ The proto_ attribute points to the prototype of the Object function ; and Object.prototype is also an object, which also has a _proto_ attribute, but __proto__ has no upper-level prototype that can be pointed to, so its value is null; that is, as shown in the figure below :

insert image description here

The final picture is actually the picture of the prototype chain that you saw at the beginning. It is actually very simple. You can draw it yourself if you have nothing to do. Remember and understand more!

The above is my personal understanding. If there is any mistake, please leave a message to point out. Let's learn together and make progress together!

Guess you like

Origin blog.csdn.net/qq_44182284/article/details/120997035
Recommended