js review: prototype chain

Posted by billspeg on Wed, 08 May 2019 06:15:04 +0200

Prototype chain

The prototype chain is actually a mechanism of inheritance in JavaScript. Before we understand the prototype chain, we should first understand several concepts: this, ordinary object and function object, constructor, new.

this

This is a confusing concept for many people, but to understand the prototype chain we have to understand what this is.

First of all, this can only exist in existence and function.

Secondly, this is the context in which the current function is located. Simply enough, it can be understood that this returns an object in which the current function is located. That is to say, to know what this is, we just need to focus on who calls the function in which this is located.

The following code zhao.sayName() is the sayName function that Zhao calls, so this in sayName naturally refers to zhao. The lower var liName = zhao.sayName statement assigns the sayName function to liName. Calling liName is equivalent to calling sayName directly at the top level, that is, under windows. The direction of this is naturally the top object of windows.

    var name = "Li"
    var zhao = {
        name: "Zhao",
        sayName: function () {
            console.log(this.name);
        }
    }
    zhao.sayName() // Zhao
    var liName = zhao.sayName;
    liName() // Li

Ordinary Objects and Functional Objects

Everything in JavaScript can be regarded as objects, but in fact objects are also different. Objects are divided into ordinary objects and function objects.

    // Common object
    var o1 = {}
    var o2 = new Object()
    var o3 = new f1()
    // Function object
    function f1(){}
    var f2 = function(){}
    var f3 = new Function()

    console.log(typeof f1); //function
    console.log(f1.prototype); //true
    console.log(typeof f2); //function
    console.log(f2.prototype); //true
    console.log(typeof f3); //function
    console.log(f3.prototype); //true

    console.log(typeof o1); //object
    console.log(o1.prototype); //undefined
    console.log(typeof o2); //object
    console.log(o2.prototype); //undefined
    console.log(typeof o3); //object
    console.log(o3.prototype); //undefined

All objects constructed by function are function objects, and only function objects have prototype attributes. Ordinary objects do not have prototype attributes.

Prototype prototype

What is prototype?

When we create a function, the compiler automatically creates a prototype attribute for the function, which points to an object that contains the constructor attribute, which in turn defaults to the original function. It reads a bit around right, probably like this.

    function Person() {
    //    prototype = {
    //        constructor: Person,
    //    }
    }

Each function object has a prototype attribute, which in my opinion means:

  1. Template for creating objects
  2. Public shared space

You will understand these two points when you learn the new command below.

Constructor constructor

One use of function objects is constructors, through which an instance of a function object (ordinary object) can be constructed.

    function Person(name, age ){
        this.name = name;
        this.age = age;
        this.sayHello = function(){
            console.log(`Hello! my name is ${this.name}`);
        };
    }

    var person1 = new Person("kidder", 28);
    person1.sayHello(); // Hello! my name is kidder
    console.log(person1.constructor); //[Function:Person]

According to convention, constructor names begin with capital letters and non-constructors begin with lowercase letters. A common object constructed by a constructor has a constructor property that points to the constructor of the object.

new command

Working mechanism of new command

  1. Create an empty object as an instance of the object to be returned
  2. Point the prototype of this empty object (proto) to the prototype attribute of the constructor
  3. Assign this empty object to this inside the constructor
  4. Execute code inside the constructor

Prototype chain

Let's look at what happens when a constructor builds a common object.

    var Person = function (name) {
        this.name = name;
        this.age = 18;
    };
    Person.prototype.sayHello = function(){
        console.log(`Hello! my name is ${this.name}`);
    };
    var li = new Person("Li");
    console.log(li.name); // Li
    console.log(li.age); // 18
    li.sayHello(); // Hello! my name is Li
  1. Create an empty object as an instance of the object to be returned
    {}
  1. Point the prototype of this empty object (proto) to the prototype attribute of the constructor
    {
        __proto__:Person.prototype;
    }
  1. Assign this empty object to this inside the constructor
    this = {
        __proto__:Person.prototype;
    }
  1. Execute code inside the constructor

       this = {
            __proto__:Person.prototype;
           name: "Li";
           age: 18;
       }

So there are only name and age attributes in the object li. Why does li.sayHello() output Hello! my name is Li?

This is the prototype chain. When a given attribute is not found in the current object, it will be searched upstream along the _proto_ attribute until the _proto_ attribute points to null. If the specified attribute is found, the search will be truncated and stopped.

The above figure is the prototype chain system of the whole JavaScript. In order to make this figure more intuitive, I put forward the prototype attribute of the constructor separately. Well, it can be drawn inside the constructor, but at the same time, because the object is a reference type, there is nothing wrong with it.

proto and prototype

These two attributes are often confused by us, so let's review them later.

prototype: Attributes that only function objects possess. They are used to store shared attributes and methods of instances that constructors want to construct. They are mainly used to instantiate constructors.

Proto: All objects have attributes. It points to the upper objects of the current object on the prototype chain. Its main function is to let the compiler find specific attributes and methods on the prototype chain composed of _proto_ attributes.

supplement

Shared attributes of prototype

    var Person = function (name) {
        this.name = name;
        this.age = 18;
    };
    Person.prototype.sayHello = function(){
        console.log(`Hello! my name is ${this.name}`);
    };
    var li = new Person("Li");

    var Person1 = function () {
    };
    Person.prototype.name = "Li"
    Person.prototype.age = 18
    Person.prototype.sayHello = function(){
        console.log(`Hello! my name is ${this.name}`);
    };

    var Li = new Person1();

What's the difference between Person and Person 1 constructors?

Generally speaking, attributes and methods written in prototype prototype objects are common. That is to say, attributes written in constructors will be redefined in new objects when building ordinary objects. That is to say, from the memory point of view, more memory space will be occupied. So, we will write all attributes and methods of constructors in prototype prototype prototype prototypes.

But prototype functions also have drawbacks:

  1. Not flexible enough
    var Person = function () {
    };
    Person.prototype.name = "Li"
    Person.prototype.age = 18
    Person.prototype.sayHello = function(){
        console.log(`Hello! my name is ${this.name}`);
    };

    var li = new Person();
    var zhao = new Person();

All objects constructed in this way are templates, and although we can modify them under the current object, they are not elegant, irregular and, in a sense, a waste of memory.

  1. Modifications to reference types are shared entirely
    var Person = function () {
    };
    Person.prototype.name = "Li"
    Person.prototype.age = 18
    Person.prototype.friends = ["ZhangSan", "LiSi"]
    Person.prototype.sayHello = function(){
        console.log(`Hello! my name is ${this.name}`);
    };

    var li = new Person();
    var zhao = new Person();
     li.friends.push("WangWu");
    console.log(zhao.friends); // [ 'ZhangSan', 'LiSi', 'WangWu' ]

In JavaScript, basic type modifications can explicitly truncate the prototype chain by creating or modifying attributes under the current object, but, like arrays, the value of a reference type of object can also truncate the prototype chain by creating the attributes in the current object, but if you don't pay attention to it, you may directly modify the prototype.

Combination of constructor and prototype

So it's elegant to use constructors to define instance attributes and prototypes to define methods and shared attributes.

    function Person(name, age){
        this.name = name;
        this.age = age;
        this.friends = ["ZhangSan", "LiSi"];
    }
    Person.prototype.sayHello = function(){
        console.log(`Hello! my name is ${this.name},${this.age}Year old`);
    };
    var li = new Person("li", 18);
    var zhao = new Person("zhao", 16);
    li.sayHello();
    // Hello! my name is li, 18 years old
    zhao.sayHello();
    // Hello! my name is zhao,16 years old
    li.friends.push("WangWu");
    console.log(zhao.friends);
    // [ 'ZhangSan', 'LiSi' ]

Several Ways to Create Objects

  1. Constructor approach

    Method 1 Constructs a New Object with Constructor

    var A = function () { };
    var a = new A();
    console.log(a.constructor); // [Function:A]
    console.log(a.__proto__ === A.prototype); //true

  1. Literary Quantity

    The essence of Fa 2 is the same as that of Fa 1, which is implicitly calling the native constructor Object to construct new objects.

    var a = {};
    // var a = new Object();
    console.log(a.constructor); // [Function:Object]
    console.log(a.__proto__ === Object.prototype); //true

  1. create mode

    Method 3 Object.create is to create a new object using a common object as a template

    var a1 = {a:1}
    var a2 = Object.create(a1);
    console.log(a2.constructor); // [Function:Object]
    console.log(a2.__proto__ === a1);// true
    console.log(a2.__proto__ === a1.prototype); //false

So in addition to the way Object.create creates objects, it can be said that _ proto == constructor. prototype;

constructor

When we talked about prototype, we used item-by-item assignment to assign prototype attributes. So what happens when I assign objects directly to prototype attributes?

    function Person() { }
    Person.prototype = {
        name : "Li",
        age : 18,
        sayHello : function () {
            console.log(`Hello! my name is ${this.name},${this.age}Year old`);
        }
    };
    var li = new Person();
    console.log(li instanceof Object);        // true
    console.log(li instanceof Person);        // true
    console.log(li.constructor === Person);    // false
    console.log(li.constructor === Object);    // true
    console.log(Person.prototype.constructor);  // Object

At this point, we find that the constructor of the li object we built no longer points to its constructor Person, but to Object, and the constructor of Person prototype Person.prototype also points to Object. What is the reason?

Actually, the roots are in Person.prototype, as we mentioned above, when we write constructors, we actually do.

    function Person() {
    // prototype = {
    //    constructor : Person
    // }
    }

When we construct the Person constructor, the compiler automatically generates an object with the constructor attribute pointing to Person and assigns this object to Person.prototype. We also know that the object in js is a reference type. When we use Person.prototype.name =..., we actually modify this object, while using Person.prototype = {...} actually will The original pointer to this property points to another newly created object rather than the one automatically created by the original compiler:

The constructor attribute of li is naturally inherited from Person.prototype, so the constructor is naturally changed. If the constructor attribute is very important in the programming process, the following way can be used

    function Person() { }
    Person.prototype = {
        constructor: Person
        name : "Li",
        age : 18,
        sayHello : function () {
            console.log(`Hello! my name is ${this.name},${this.age}Year old`);
        }
    };
    
    var li = new Person();
    console.log(li instanceof Object);        // true
    console.log(li instanceof Person);        // true
    console.log(li.constructor === Person);    // true
    console.log(li.constructor === Object);    // false
    console.log(Person.prototype.constructor);  // Person

Conclusion:

Reference: JavaScript Advanced Programming

This is my summary and Reflection on the part of JS prototype chain. It is also the first formal technical document I wrote. If there are any mistakes, you are welcome to criticize and correct them.

Topics: Javascript Attribute Windows Programming