Detailed js prototype chain

First look at the interview questions below and think about the results.

    Object.prototype.test1 = function () {
      console.log('test1');
    };
    
    Function.prototype.test2 = function () {
      console.log('test2');
    };

    function Fun() {
      this.a = 1;
    }

    var obj = new Fun();

    console.log(obj.test1);
    console.log(obj.test2);




Answer:
Insert picture description here


obj.test1 outputs a function, while obj.test2 outputs undefined.

In order to answer this question, a deep understanding of the javascript prototype chain is required.



Knowledge points

What is the js prototype chain

Before learning the prototype chain, first understand three basic concepts: constructor, instance object, prototype object

Constructor

The constructor is also a function, but it has one more function than the ordinary function, and it can create an object when called with the new keyword.

 function student(){
    this.name = "张三"; 
 }
 
 var stu1 = new student(); //创建对象
	
 console.log(stu1.name); //输出张三

The student function defined above is a constructor, which generates a new object by using the new keyword

Instance object

The instance object is the new object returned after calling the constructor using the new keyword. Corresponds to stu1 in the above code

Prototype object

The prototype object is also an object, which is an object pointed to by the prototype of the constructor.

 function student(){
    this.name = "张三"; 
 }

 student.prototype.run = function(){console.log("奔跑");}
 
 var stu1 = new student(); //创建对象
	
 stu1.run()  //打印'奔跑'

student.prototype is the prototype object.After adding properties and methods to the prototype object, the instance object can call the properties and methods on the prototype object.


It is worth noting that Object, Function, Array, String, Number, etc. are all constructors. By using the new keyword, you can create the corresponding instance object, and add properties and methods to the prototype of the constructor, and the corresponding instance object can be called.

The instance object can access the properties and methods on the prototype object, and the prototype object may inherit from another prototype object. In this way, the instance object of the first level can access the properties and methods of the second level prototype object, and it can also access the third level prototype. The properties and methods of the object. The chain formed in this way is the prototype chain. The following diagrams are used to understand the structure of the prototype chain.



The architecture of the prototype chain

Insert picture description here


The rectangle in the figure above is the constructor, the ellipse is the prototype object, and the rectangle with rounded corners is the instance object.

The variable array in the above figure is an example. Array inherits the prototype object of Array, and the prototype object of Array inherits the prototype object of Object. At this time, array, prototype object of Array and prototype object of Object form a prototype chain.

The properties and methods defined by high-level objects on the prototype chain can be called and accessed by low-level objects.

The status of Object.prototype

The highest level of the prototype chain is Object.prototype. All objects inherit Object.prototype. If properties and methods are defined on Object.prototype, all objects (except null) can be inherited and used.

  Object.prototype.test1 = 123;
  var obj = {};
  console.log(obj.test1); //输出123
  
  obj.test1 = 456;
  
  console.log(obj.test1); //输出456,倘若子对象定义了与原型链上的对象相同的属性和方法时,子对象会覆盖
  console.log(typeof null) // 输出 "object"
  console.log(null.test1) //报错,null虽然也是对象,但是它不能调用任何属性和方法



Constructor and prototype object

Object, Function, Array, String, RegExp are all constructors, and the prototype object on the right side of the above figure can be accessed through .prototype.

Print out the above prototype object, and you can see that there is no difference between the prototype object and the ordinary object, but it defines a lot of methods.

Insert picture description here


Object inheritance

Whether it is an instance object or a prototype object, you can use __proto__ to get the parent's prototype object.

var array = new Array();

array.__proto__ === Array.prototype; // true,通过__proto__属性可以获取父级的原型对象

Array.prototype.__proto__ === Object.prototype //true

//Object.prototype是所有对象的最高层,它再往一层就为null了
console.log(Object.prototype.__proto__) //输出 null

Array is an instance object, it can use all the properties and methods of the Array prototype object, and it can also use the properties and methods of the Object prototype object.
 Object.prototype.test1 = 123;
 
 Array.prototype.test2 = 456;

 var array = new Array(); 
 
 console.log(array.test1); //输出123
 console.log(array.test2); //输出456



What is the difference between a commonly defined object and a new object

Many times define objects like to use var obj = () directly, var array = [], var fun = function()(), what is the difference between them and new objects.

    var obj1 = {};
    var obj2 = new Object();
    
    obj1.__proto__ === obj2.__proto__ // 打印 true,都是指向了Object.prototype 
    
    var array1 = [];
    var array2 = new Array();
    
    array1.__proto__  === array2.__proto__ // 打印 true,都是指向了Array.prototype

It can be seen from the above that there is no difference between using var definition and new objects, but sometimes using new to create objects is more powerful.

  var fun1 = function(){
      console.log(123);
  }

 var code = "console.log(456)";
 
 var fun2 = new Function(code);
 
 fun2(); // 输出456

If the executed code is a string, when the function object is created using the constructor Function, the function body can be dynamically changed, achieving an effect similar to eval.


Function和Object

From the above description, Object.prototype is the ancestor of all objects. The parent of Function.prototype is Object.prototype

  Function.prototype.__proto__ === Object.prototype //输出 true

The relationship between the prototype object of Function and the prototype object of Object is clear, let's look at the constructor Object and Function.

Object is a constructor, and it is also a function (a function itself is an object). As long as it is a function, it inherits the properties and methods of Function.prototype.

Function.prototype.test = "测试";
console.log(Object.test); //输出 "测试"

Define properties and methods on Function.prototype, then all functions can be inherited and called.

Object和Object.prototype

Object.prototype.test = "测试";
console.log(Object.test); //输出 "测试"

Define any properties and methods on Object.prototype, not only Object, Function, Array, RegExp, etc. can be inherited and called.

Take Object as an example. Object is a constructor and also a function object. Object inherits from Function.prototype, and Function.prototype inherits from Object.prototype. Thus Object, Function.prototype and Object.prototype constitute a prototype chain.

 Object.__proto__.__proto__ === Object.prototype; //输出 true

to sum up

  • When analyzing the problems related to the prototype chain, first determine whether the end variable is used as a constructor or a function object according to the context. For example, Function can be used as a constructor or a function object. It can be called when used as a constructor. Prototype gets The prototype object, when used as an instance object or prototype object, can call __protp__ to find the parent's prototype object.

    Function.prototype === Function.__proto__ // 输出true
    

    Function as a constructor function calls prototype to get the parents of all function objects. As a normal function, Function can also get the parents of all function objects through __proto__. Therefore, they are equal.

  • Only objects on a prototype chain constitute an inheritance relationship. For example, Array.prototype.test = "Test"; var obj = {}; At this time, obj cannot get the test attribute.



Application of the prototype chain


Object property acquisition

 var obj1 = {
   a:1
 };
  var obj2 = {
   b:2
 };
  var obj3 = {
   c:3
 }
 obj1.__proto__ = obj2;
 obj2.__proto__ = obj3;

console.log(obj1.c); //输出3

Create 3 objects, make obj1, obj2 and obj3 and Object.prototype form a prototype chain by changing __proto__.

When obj1 gets the value of the c attribute, it will first look for it from obj1, jump to the previous layer obj2 if it is not found, and continue to jump to the next layer if it is still not found, and finally find the c output in obj3.

for in loop

  var obj1 ={
    a:1
  }
  var obj2 = {
    b:2
  };
  obj1.__proto__ = obj2;
 
 for(var key in obj1){
   console.log(key); //输出 a b
 }

Although the code only loops obj1, the for in loop mechanism will obtain all enumerable properties and methods on the entire prototype chain.

Is there a way to only find out the properties and methods defined by the object itself, and abandon the definition on the prototype chain? (It can be done through hasOwnProperty)

  var obj1 ={
     a:1
  }
  var obj2 = {
     b:2
  };
  obj1.__proto__ = obj2;
 
 for(var key in obj1){
   if(obj1.hasOwnProperty(key)){
	 console.log(key); //只输出a
  }
}



Problem solving

    Object.prototype.test1 = function () {
      console.log('test1');
    };
    
    Function.prototype.test2 = function () {
      console.log('test2');
    };

    function Fun() {
      this.a = 1;
    }

    var obj = new Fun();

    console.log(obj.test1);
    console.log(obj.test2);

Now let's look at the original interview question. obj is an ordinary object, and its parent is Fun.prototype.

obj, Fun.prototype and Object.prototype form a prototype chain, so test1 can get it, and test2 is undefined.


The test2 method is defined on Function.prototype, which allows all function objects to obtain test2, but ordinary objects cannot. As follows:

console.log(Fun.test2 ); //输出 test2函数

Guess you like

Origin blog.csdn.net/brokenkay/article/details/109724464