In-depth explanation of Javascript prototype and prototype chain

Source: Internet
Author: User
Tags constructor inheritance tidy

1. Common objects and function objects

In JavaScript, everything is an object! But there are also differences between objects. It can be divided into common objects and Function objects. Objects and functions are built-in Function objects of JS. The following is an example

Function f1 (){};
Var f2 = function (){};
Var f3 = new Function ('str', 'console. log (str )');

Var o3 = new f1 ();
Var o1 = {};
Var o2 = new Object ();

Console. log (typeof Object); // function
Console. log (typeof Function); // function
Console. log (typeof o1); // object
Console. log (typeof o2); // object
Console. log (typeof o3); // object
Console. log (typeof f1); // function
Console. log (typeof f2); // function
Console. log (typeof f3); // function
    
In the preceding example, o1 o2 o3 is a common object, and f1 f2 f3 is a function object. How to differentiate is actually very simple. All objects created through new Function () are Function objects, while others are common objects. F1 and f2 are all created using the new Function () method. Function objects are also created through New Function.

II. Prototype object


In JavaScript, every time an object (function) is defined, the object contains predefined attributes. One property of the function object is prototype. Note: common objects do not have prototype, but have the _ proto _ attribute.

The prototype object is actually a common object (except Function. prototype, which is a Function object, but it is very special. It does not have the prototype attribute (previously mentioned that Function objects all have the prototype attribute )). See the following example:
Function f1 (){};
Console. log (f1.prototype) // f1 {}
Console. log (typeof f1. prototype) // Object
Console. log (typeof Function. prototype) // Function, this special
Console. log (typeof Object. prototype) // Object
Console. log (typeof Function. prototype. prototype) // undefined

From the output of console. log (f1.prototype) // f1 {}, we can see that f1.prototype is an f1 instance object. When f1 is created, it creates an instance object and assigns prototype to it. The basic process is as follows:
Var temp = new f1 ();
F1. prototype = temp;

Therefore, why is Function. prototype a Function object solved? All objects generated by new Function () are Function objects, so temp1 is a Function object.
Var temp1 = new Function ();
Function. prototype = temp1;

What is the prototype used? It is mainly used for inheritance. For example:
Var person = function (name ){
This. name = name
};
Person. prototype. getName = function (){
Return this. name;
  }
Var zenders = new person ('hangzhou ');
Zjh. getName (); // zhangjiahao

From this example, we can see that by setting the property of a function object for person. prototype, a common object from the person instance (in this example: z.pdf) inherits this property. The following prototype chain is required for the implementation of inheritance.

III. Prototype chain


When JS creates an object (whether a common object or a function object), it has a built-in attribute called _ proto _, which is used to point to the prototype of the function object that creates it. The preceding example is used as an example:

Console. log (zwon. _ proto _ = person. prototype) // true

Similarly, the person. prototype Object also has the _ proto _ attribute, which points to the prototype of the function Object that creates it.

Console. log (person. prototype. _ proto _ = Object. prototype) // true

The Object. prototype Object also has the _ proto _ attribute, but it is special and is null.

Console. log (Object. prototype. _ proto _) // null

We concatenate _ proto _ until the Object. prototype. _ proto _ is null. As shown in the following figure:


IV. Memory structure


For a deeper and more intuitive understanding, we will draw the above memory structure diagram:

Drawing conventions:

Explanation:
1. Object. _ proto _ = Function. prototype // true
An Object is a Function Object created through new Function (). Therefore, Object. _ proto _ points to Function. prototype.

2. Function. _ proto _ = Function. prototype // true
Function is also an object Function and is created through new Function (). Therefore, Function. _ proto _ points to Function. prototype.

It seems that you are created by yourself and it does not conform to the logic, but think about it carefully. The real world is similar. How did you come from your mom, you have been born ,...... Where did the ape come from when it evolved? Keep tracing ......, Is none. (NULL creates everything)
As the moral Sutra says, "No, the beginning of the world ".

3. Function. prototype. _ proto _ = Object. prototype // true
In fact, I am also a little confused, but I can try to explain it.
Function. prototype is a Function object. In theory, its _ proto _ should point to Function. prototype, which is itself, pointing to itself, without significance.
JS has always stressed that everything is an Object, and function objects are also objects. It recognizes the ancestor and points to Object. prototype. Object. prototype. _ proto _ = null to ensure that the prototype chain can end normally.

V. constructor


The prototype object has a predefined constructor attribute, which is used to reference its function objects. This is a type of circular reference.
Person. prototype. constructor === person // true
Function. prototype. constructor === Function // true
Object. prototype. constructor === Object // true

Complete the above memory structure:


Note the following two points:
(1) Note that Object. constructor === Function; // true itself, the Object is constructed by the Function.
(2) how to find the constructor of an object is to find the object pointed to by the first constructor attribute on the prototype chain of the object.

VI. Summary


1. Prototype and prototype chain are a model inherited by JS implementation.
2. The prototype chain is formed by _ proto _ rather than prototype.

If you want to understand this sentence in depth, let's take another example to see if you have really understood it before?
Var animal = function (){};
Var dog = function (){};

Animal. price = 2000 ;//
Dog. prototype = animal;
Var tidy = new dog ();


Console. log (dog. price) // undefined
Console. log (tidy. price) // 2000

Why? Draw a memory diagram:


What is the problem? Run dog. the price attribute is not found. Although the animal to which prototype points has this attribute, it does not search for it along this "chain. Similarly, run tidy. this attribute is not available at price, but _ proto _ points to animal, which will be searched along this chain. animal has the price attribute, so tidy. price output 2000. It is concluded that the real formation of the prototype chain depends on _ proro __, rather than prototype.
Therefore, if dog. _ proto _ = animal is specified in this way. Dog. price = 2000.

In the end, although it is not very accurate, it may be helpful to understand the prototype.


Father (function object), Mr. Has a eldest son (prototype), that is, your eldest brother. His father bought many toys for your eldest brother. When you were born, the family ties between you (_ proto _) will naturally let you own your eldest brother's toys. Similarly, you have a eldest son and bought many toys for him. When you regenerate your son, your youngest son will naturally own all the toys of your eldest son. As for whether they will fight, this is not our case.
So you inherited from your eldest brother and confirmed the sentence "brother-in-law!


Js in-depth prototype chain

I mentioned js scope and lexical analysis in the previous section. Today I talked about the prototype chain and it took some time to write this article because it is a bit abstract, it is not easy to express it in a language. The article I want to write is not simply a copy of the official API, but a process of exploring and summarizing my own knowledge, and the problems encountered in this process are all written one by one. I think most people should also have this question, and then find the answer with the doubt. After you solve this question, I feel very fulfilled. Let's talk about the prototype chain. To understand the prototype chain, we must start with a simple process. What is prototype? First, let's look at the code:

Function funcA (){
This. show = function (){}
}
Console. log (funcA. prototype );



From this figure, we can see that the prototype of funcA is an Object and its name is funcA. There is a constructor attribute pointing to funcA, and a _ proto _ pointing to Object. prototype (how can this be obtained? You can see that the constructor attribute Under _ proto _ points to an Object, indicating that it is the prototype of the Object. The funcA prototype is roughly written as follows:


FuncA. prototype = {

Constructor: funcA,

_ Proto __: Object. prototype


}



PS: where does _ proto _ come from? In js, each object has an internal hidden attribute named _ proto _ pointing to its prototype object (named _ proto __in chrome and firefox __, and can be accessed), while common objects do not have the prototype attribute and only have the _ proto _ attribute. The figure below is displayed based on the above result.


Now we have a general understanding of the prototype. Anyway, it is such an object. It has several unusual attributes and continues to deepen. When we use funcA to create an object, what will happen again?


Function funcA (){
This. show = function (){}
}
Console. log (funcA. prototype );
Var a = new funcA ();
Console. log ();
Console. log (a. _ proto __);
Console. log (a. _ proto _ = funcA. prototype );
Console. log (a. _ proto _. constructor === funcA );

The running result is as follows:

The above result is analyzed. a is the object created by funcA. It has the methods in funcA and also has a _ proto __, which can be expressed:


Var a = {

Show: function (){.....},

_ Proto __: funcA. prototype

}



Similarly, we can get the following figure:


To sum up the above process, from the perspective of appearance, when funcA creates an object, this object a "copies" the methods in funcA ", then a prototype pointing to the _ proto _ property is generated.

In fact, the new object is created in three steps.

1. An empty object a ={} is created {};
2. Point the _ proto _ Member of this empty object to the prototype member object of the funcA function object.
3. Replace this pointer of the funcA function object with a and then call the funcA function. Therefore, we assign a new method member to object.

The specific implementation code can be expressed as follows:


Var a = {};
A. _ proto __= funcA. prototype;
FuncA. call ();

The following code is used for verification:
Function funcA (){
This. show = function (){}
}
Console. log (funcA. prototype );

Var B = new funcA (); // new to build

Var a ={}; // define manually defined
A. _ proto __= funcA. prototype;
FuncA. call ();
Console. log ();
Console. log (B );



The implementation result is as follows. We can see that the internal methods of a and B are completely the same. The only difference is that a comes from the prototype of the Object, and B comes from the prototype of funcA (resulting in different output names ).


Now we can make a summary of the above processes. What is the prototype? All Js functions have a prototype. Its essence is to reference an object. It is called prototype (it is still a bit difficult to understand, but it should be understood as a mechanism of js first. As for why, I will discuss it later ). When constructing a common object of a new object, a _ proto _ property is generated pointing to it.

Continue digging down:

Now, we have understood the prototype and Object generation of js clearly. The following is simple. The Secret of the Object in the above figure is unveiled below: funcA. prototype. _ proto _ What is the Object pointing? What is its source? The output result of the current value on the console is as follows:


Based on the above experience, we can infer that _ proto _ points to the prototype of a function, that is, xxx. prototype = funcA. prototype. _ proto __, this xxx should be the constrcutor of the current Object at the same time. Let's take a look at the conjecture.


The above red box shows the output result. We can say that we are right. Similarly, since an Object is an Object, what is its prototype and _ proto?


The above content shows that the final prototype is null, which indicates that the Object is generated. prototype: the prototype of the object "parent" is null. To sum up the above results, we can sum up the following figure:


Well, the prototype is almost Discussed. Let's talk about some special functions and the code above.

Var foo = new Function ("var str = 'C'; console. log (str );");
Foo ();
Console. log (foo );
Console. log (foo. prototype );
Console. log (foo. _ proto __);
//

The running result is as follows:


The above results show that the Object generated by the Function is still a Function Object. foo. _ proto _ is an empty Function Object, and foo. prototype is an instance Object of the Object. It can be inferred from the above, foo. _ proto __= = Function. prototype; releases the Function for true. prototype = function () {} (an empty function). Since function and prototype are a function object, what is its prototype? Check Function. prototype. prototype =? What is the value?

It can be seen that this function () {} has no prototype. It should be the end of the prototype, that is, all function _ proto _ are Function () {}, that is, function. prototype, that is, all functions are an instance object of Function, which explains that everything in js is an object.

Another thought: we have found the root of the Function. Where is the root of the Function. prototype object? Function. prototype has reached the end of the prototype. How does it come from? Let's take a look at Function. prototype. _ proto __=? What is this?


From this result, we can see that Function. prototype. _ proto _ is an instance Object of an object. We have learned from the prototype analysis above that the final _ proto _ point of this "Object" is null. Although we have many questions so far, we feel that everything has become clear. Function objects and common objects are the same, and the final point is null. To sum up, see the following figure:



The figure above shows the relationship between all the elements after analysis. It looks clear that the endpoints of all the _ proto _ elements are null. If the null element is left blank, that is, the base Object of all common objects is an Object (prototype of the Object function), including common objects of the Object type. Likewise, all functions _ proto _ are function () {} (Function. prototype), including the Function itself. After reading this, is there a feeling of being a (null object), a second life, and a second life?

Some people may also notice the red Function of the right positive solution, which is also generated by him. Don't worry about it first. To better illustrate the figure above, let's look at the following code description:

Function funcA (){}
Function funcB (){}
Console. log (funcA. _ proto __);
Console. log (funcB. _ proto __);
Console. log (funcA. _ proto _ = funcB. _ proto __);
Console. log (funcA. _ proto _ = funcB. _ proto _ & funcB. _ proto _ = Number. _ proto _ & Number. _ proto _ = Function. _ proto __);
Console. log (Function. prototype = Function. _ proto __);

The running result is as follows:



The above running results also prove our idea that Function is a special object, and its instance also comes from itself, because its prototype is the source of all functions, it is also a Function, so it is not surprising. prototype = Function. _ proto _ is true. Similarly, the root causes of all function objects are the same, so the following equations are true.

Function funcA (){}
Function funcB (){}

FuncA. _ proto _ = funcB. _ proto __;
FuncB. _ proto _ = Number. _ proto __;
Number. _ proto _ = Function. _ proto __;
Function. _ proto __== Function. prototype
Number. _ proto _ = Function. prototype; // true
Boolean. _ proto _ = Function. prototype; // true
String. _ proto _ = Function. prototype; // true
Object. _ proto _ = Function. prototype; // true
Function. _ proto _ = Function. prototype; // true
Array. _ proto _ = Function. prototype; // true
RegExp. _ proto _ = Function. prototype; // true
Error. _ proto _ = Function. prototype; // true
Date. _ proto _ = Function. prototype; // true


After talking about this, we haven't talked about prototype chain yet. If we have understood it above, the prototype chain is so easy. If we don't talk about it, we should talk about it with code:


Var a = {};
A. _ proto _. value = "";
A. show = function (){
Console. log (this. value );
 }
A. show ();


The result of running this code is to output a letter "a", but we can see that the field of value does not exist in the object of a, but it can also be output, because there is a value attribute on its _ proto _, js will search for the attribute along the _ proto _ when searching for it. This is the prototype chain we will talk about. The principle is simple: if the current property or method (value) cannot be found in the current object, it will start searching along the prototype chain and traverse the entire prototype chain. Once it is found, returns the method for obtaining the first property found. If not, returns undefined.

After talking about this, what is the role of prototype chain? Many may say that it can be used for inheritance, but that's right, but we still need to understand why it can be inherited and why funcA. prototype = new funcB (); This achieves the so-called inheritance. The code is as follows:


Function funcA (){
This. show = function (str ){
Console. log (str );
    }
}
Function funcB (){
This. read = function (){
    }
}
Var a = new funcA ();
FuncB. prototype =;
A. show ("");
Var B = new funcB ();
B. show ("B ");
 

The running result is as follows:


This is a very common method. We can see that B can call the funcA method. Why? Let's draw a prototype diagram below.


The figure above should be clear, because the prototype of funcB is a, which leads to B. _ proto __= a, so B can access the method in a Along the prototype chain, so that it realizes inheritance-prototype chain inheritance, also known as prototype inheritance.

The current inheritance method does not need to be written in this way. The principle is clear, so there is nothing to change it. Let's look at a simple and crude prototype inheritance:


Function funcA (){
This. show = function (str ){
Console. log (str );
    }
}
Function funcB (){
This. read = function (){}
}
Var a = new funcA ();
Var B = new funcB ();
B. _ proto _ =;
A. show ("");
B. show ("B ");


In this way, it is the same as the output result above, but in this case, only object B inherits the method in a, but the new object of funcB is generated, but there is no method in:

For example:


Var c = new funcB ();
C. show ("c"); // error


Of course, there are many implementation methods. I will talk about the three inheritance methods of js below. If the length is not large, it will be written together with the js's this. The following describes implementation methods for reference. The reason is as follows:


Function funcA (){
This. show = function (str ){
Console. log (str );
    }
}
Function funcB (){
This. read = function (){}
}
Var a = new funcA ();
Var B = new funcB ();
FuncA. call (B); // use call
A. show ("");
B. show ("B ");

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.