Detailed Explanation of JS Prototype and Prototype Chain (Deep Learning)

1. Ordinary objects and function objects. (Everything is an object)

In JavaScript, it is divided into ordinary objects and function objects . Object and Function are function objects that come with JS. The following example illustrates:

var obj1 = {};

var obj2 = new Object();

var obj3 = new fun1();


function fun1(){};

var fun2 = function(){};

var fun3 = new Function();

 
console.log(typeof Object);   //function

console.log(typeof Function); //function  


console.log(typeof obj1);     //object

console.log(typeof obj2);     //object

console.log(typeof obj3);     //object


console.log(typeof fun1);     //function

console.log(typeof fun2);     //function

console.log(typeof fun3);     //function   




 

In the above example, obj1 obj2 obj3 are common objects, fun1 fun2 fun3 are function objects. How to distinguish is actually very simple. All objects created through new Function() are function objects, and others are ordinary objects. fun1, fun2, in the final analysis, are all created by way of new Function(). Function Objects are also created through New Function() .

Be sure to distinguish between ordinary objects and function objects, which we will often use below.

As shown in the picture:

 

 

2. Constructor

 

Let's review the knowledge of the constructor first:

function Fun(name, age, job) {

 this.name = name;

 this.age = age;

 this.job = job;

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

}

var fun1 = new Fun('dragon1', 29, 'hello');

var fun2 = new Fun('dragon2', 26, 'hello');

Both fun1 and fun2 in the above example are instances of Fun . Both instances have a constructor (constructor) property, which (which is a pointer) points to Fun. Right now:

  console.log(fun1.constructor == Fun); //true

  console.log(fun2.constructor == Fun); //true

We have to remember two concepts (constructor, instance):

Both fun1 and fun2 are instances of the constructor Fun.

Note: The instance's constructor attribute (constructor) points to the constructor.

3. Prototype object

In JavaScript, whenever an object (a function is an object) is defined, the object will contain some predefined properties. Each function object has a prototype attribute, which points to the prototype object of the function .

 

The following example illustrates:

function Fun() {}

Fun.prototype.name = 'dragon';

Fun.prototype.age  = 28;

Fun.prototype.job  = 'Web';

Fun.prototype.sayName = function() {

  alert(this.name);

}

var fun1 = new Fun();

fun1.sayName(); // 'dragon'

var fun2 = new Fun();

fun2.sayName(); // 'dragon'


console.log(fun1.sayname == fun2.sayname); //true

 Notice:

Every object has a __proto__ attribute, but only function objects have a prototype attribute.

1. So what is a prototype object?

According to the example above:

Fun.prototype = {

   name:  'dragon',

   age: 28,

   job: 'Web',

   sayName: function() {

     alert(this.name);

   }

}

A prototype object, as the name suggests, is an ordinary object. From now on you have to keep in mind that the prototype object is Fun.prototype.

By default, all prototype objects will automatically get a constructor (constructor function) attribute, which (a pointer) points to the function (Fun) where the prototype attribute is located.

If the above sentence is a bit of a mouthful, let me explain it in detail:

如:var F = Fun.prototype ;

F has a default constructor attribute, which is a pointer to Fun.

即:Fun.prototype.constructor == Fun;  //true

The instance's constructor attribute (constructor) points to the constructor:

fun1.constructor == Fun;      //true

2. Why does fun1 have a constructor attribute?

      Because fun1 is an instance of Person.

3. Why does Fun.prototype have a constructor attribute?

     Fun.prototype (you think of it as F) is also an instance of Fun.

That is, when Fun is created, an instance object of it is created and assigned to its prototype. The basic process is as follows:

 var  F= new Fun();

 Fun.prototype = F;

Conclusion: The prototype object (Fun.prototype) is an instance of the constructor (Fun).

Prototype objects are actually ordinary objects (except for Function.prototype, which is a function object, but it is very special, and it does not have a prototype attribute (as mentioned earlier, function objects have prototype attributes)). See the example below:

function Fun(){};

 console.log(Fun.prototype)                       //Fun{}

 console.log(typeof Fun.prototype)                //Object

 console.log(typeof Function.prototype)           // Function 

 console.log(typeof Object.prototype)             // Object

 console.log(typeof Function.prototype.prototype) //undefined

4. Why is Function.prototype a function object?

 var F = new Function ();

 Function.prototype = F;

All objects generated by new Function( ) are function objects .

Since F is a function object, Function.prototype is a function object

4. __proto__

When JS creates an object (whether it is a normal object or a function object), it has a built-in attribute called __proto__  , which is used to point to the prototype object of the constructor that created it.
The object fun1 has a  __proto__ attribute, the constructor that creates it is Fun, and the prototype object of the constructor is Fun.prototype, so:

fun1.__proto__ == Fun.prototype

Fun.prototype.constructor == Fun;

fun1.__proto__ == Fun.prototype;

fun1.constructor == Fun;

However, the really important thing to be clear is that this connection exists between the instance ( fun1 ) and the prototype object ( Fun.prototype ) of the constructor ( Fun ), not between the instance ( fun1 ) and the constructor ( Fun ) between. 

Note: The __proto__ attribute was added to ES6 because most browsers support it (ES5 is also supported by some browsers, but it is not yet a standard).

5. Constructor

Children's shoes who are familiar with Javascript know that we can create an object like this:
var obj = {}
which is equivalent to the following:
var obj = new Object()

obj is an instance of the constructor (Object). So:
obj.constructor === Object
obj.__proto__ === Object.prototype

A new object obj is created using the new operator followed by a constructor . The constructor (Object) itself is a function (that is, the function object mentioned above), which is similar to the above constructor Person. It's just that the function is defined for the purpose of creating new objects. So don't be intimidated by Object.

Similarly, the constructors that can create objects are not only Object, but also Array, Date, Function, etc.
So we can also construct functions to create Array, Date, Function.

var a = new Array();
a.constructor === Array;             //true
a.__proto__ === Array.prototype;     //true

var b = new Date(); 
b.constructor === Date;              //true
b.__proto__ === Date.prototype;      //true

var c = new Function();
c.constructor === Function;          //true
c.__proto__ === Function.prototype;  //true

 

The following are function objects:

typeof Boolean      'function'

typeof Number       'function'
 
typeof Date         'function'
 
typeof Array        'function'
 
typeof String       'function'
 
typeof Function     'function'
 
typeof Object       'function'
 

6. Prototype chain

Use prototypes to let one reference type inherit the properties and methods of another reference type.

Each constructor has a prototype object, the prototype object contains a pointer to the constructor (constructor), and the instance object contains an internal pointer to the prototype object (__proto__). If the prototype object is equal to an instance of another type, the prototype object at this time will contain a pointer to another prototype (__proto__), and the other prototype also contains a pointer to another constructor (constructor). If another prototype is an instance of another type... this constitutes a chain of instances and prototypes.

As shown in the picture:

 for example:

function Fun(){  
    this.type = "web";  
}  
Fun.prototype.getType = function(){  
    return this.type;  
}  
  
function Fun1(){  
    this.name = "dragon";  
}  
Fun1.prototype = new Fun();  
  
Fun1.prototype.getName = function(){  
    return this.name;  
}  
  
var fl = new Fun1();  

output: 

 fun1.__proto__ === Fun.prototype                //true

 Fun.__proto__ === Function.prototype            //true

 Fun.prototype.__proto__ === Object.prototype    //true

 Object.prototype.__proto__ === null             //true

 7. Summary:

From the above conclusions:

insert image description here

(1), the __proto__ of all function objects point to Function.prototype, which is an empty function (Empty function)

 Example:

Number.__proto__ === Function.prototype  // true
Number.constructor == Function           //true

Boolean.__proto__ === Function.prototype // true
Boolean.constructor == Function          //true

String.__proto__ === Function.prototype  // true
String.constructor == Function           //true

 (2) All constructors come from Function.prototype, even the root constructor Object and Function itself

 Example:

Function.__proto__ === Function.prototype  // true
Function.constructor == Function           //true

Array.__proto__ === Function.prototype     // true
Array.constructor == Function              //true

RegExp.__proto__ === Function.prototype    // true
RegExp.constructor == Function             //true

Error.__proto__ === Function.prototype     // true
Error.constructor == Function              //true 

Date.__proto__ === Function.prototype      // true
Date.constructor == Function               //true

  (3) Created by the JS engine only when the function is called, Math and JSON exist in the form of objects without new. Their proto is Object.prototype. as follows:

Math.__proto__ === Object.prototype      // true
Math.construrctor == Object              // true
 
JSON.__proto__ === Object.prototype      // true
JSON.construrctor == Object              //true
 

Knowing that the __proto__ of all constructors (including built-in and custom) is Function.prototype, who is the __proto__ of Function.prototype?
I believe everyone has heard that functions in JavaScript are also first-class citizens, so how can it be reflected? The following
console.log(Function.prototype.__proto__ === Object.prototype) // true
means that all constructors are also a common JS object, and properties can be added/deleted to the constructor. At the same time, it also inherits all methods on Object.prototype: toString, valueOf, hasOwnProperty, etc. (You should also understand the first sentence. We will continue to talk about the second sentence in the next section. There is no need to dig a hole, it is the same hole just now; 

Who is the proto of Object.prototype ?
Object.prototype.__proto__ === null // true

(4), Prototype

Of all the properties defined by the ECMAScript core, the most intriguing one is the prototype property. For reference types in ECMAScript, the prototype is the real place where all their instance methods are stored. In other words, methods such as toString() and valuseOf() are actually stored under the prototype name, but are accessed through the instance of the respective object.

1. When creating an object instance:

var Person = new Object()
Person is an instance of Object, so Person  inherits all the methods on Object.prototype, the prototype object of Object:

 

 

Every instance of Object has the above properties and methods.
So I can use Fun.constructor or Fun.hasOwnProperty.

2. When creating an array instance:

 

var num = new Array()
num is an instance of Array, so num  inherits all the methods on Array.prototype, the prototype object of Array:

3. When creating a function:

var fun = new Function("x","return x*x;");

//当然你也可以这么创建 fun = function(x){ return x*x }

console.log(fun.arguments)            //null  arguments 方法从哪里来的?

console.log(fun.call(window))         //NaN   call 方法从哪里来的?

console.log(Function.prototype)       // function() {} (一个空的函数)

console.log(Object.getOwnPropertyNames(Function.prototype)); 

//['length', 'name', 'arguments', 'caller', 'constructor', 'apply', 'bind', 'call', 'toString']

All function object proto points to Function.prototype, which is an empty function (Empty function)

Well, we verified that it is the empty function. But don't ignore the first half of the sentence. We enumerate all its methods, so all function objects can be used, for example:

 (5), __proto__

The __proto__ of all function objects point to Function.prototype, which is an empty function (Empty function)

First look at the JS built-in constructor:

 

var obj = {name: 'dragon'};
var arr = [1,2,3,4,5];
var reg = /hello/g;
var date = new Date;
var err = new Error('pp');

console.log(obj.__proto__  === Object.prototype) // true
console.log(arr.__proto__  === Array.prototype)  // true
console.log(reg.__proto__  === RegExp.prototype) // true
console.log(date.__proto__ === Date.prototype)   // true
console.log(err.__proto__  === Error.prototype)  // true

 Look at the custom constructor again, where a Fun is defined:

function Fun(name) {
  this.name = name;
}
var pp = new Fun('dragon');

console.log(pp.__proto__ === Person.prototype); // true

pp is an instance object of Fun, and the internal prototype of pp always points to the prototype object prototype of its constructor Fun.

Every object has a constructor property to access its constructor, so the result is also identical:

function Fun(name) {
    this.name = name
}
var pp = new Fun('jack')
console.log(pp.__proto__ === pp.constructor.prototype) // true

上面的Person没有给其原型添加属性或方法,这里给其原型添加一个getName方法:

function Fun(name) {
    this.name = name
}
// 修改原型  增加一个方法
Fun.prototype.getName = function() {}
var pp = new Fun('dragon')
console.log(pp.__proto__ === Fun.prototype)            // true
console.log(pp.__proto__ === pp.constructor.prototype) // true

It can be seen that pp.__proto__, Fun.prototype, and pp.constructor.prototype are all identical, that is, they all point to the same object.

If you set the prototype in another way, the result is a little different:

function Fun(name) {
    this.name = name
}
// 重写原型
Fun.prototype = {
    getName: function() {}
}
var pp = new Fun('dragon')
console.log(pp.__proto__ === Fun.prototype)            // true
console.log(pp.__proto__ === pp.constructor.prototype) // false

Here Fun.prototype is directly rewritten (note: the previous example is to modify the prototype). The output shows that pp.__proto__ still points to Fun.prototype instead of pp.constructor.prototype.

This is also easy to understand. What is assigned to Fun.prototype is an object literal {getName: function(){}}, and the constructor (constructor) of an object defined using the object literal method points to the root constructor Object, Object .prototype is an empty object {}, {} is naturally not equal to {getName: function(){}}. as follows:

var pp = {}
console.log(Object.prototype)                              // 为一个空的对象{}
console.log(pp.constructor === Object)                     // 对象直接量方式定义的对象其constructor为Object
console.log(pp.constructor.prototype === Object.prototype) // 为true

(5) Prototype chain. (under review)

After reading the example, you will understand:

function Fun(){}
var fun1 = new Fun();

console.log(fun1.__proto__ === Fun.prototype);             // true
console.log(Fun.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__);                   // null

console.log(Fun.__proto__ == Function.prototype);          //true
console.log(Function.prototype);                           // function(){}(空函数)

var num = new Array();
console.log(num.__proto__ == Array.prototype);              // true
console.log(Array.prototype.__proto__ == Object.prototype); // true
console.log(Array.prototype);                               // [] (空数组)
console.log(Object.prototype.__proto__);                    //null

console.log(Array.__proto__ == Function.prototype);         // true

Guess you like

Origin blog.csdn.net/qq_35404844/article/details/129981635