About constructor, prototype and prototype chain advanced version

Keywords: Javascript

This article draws lessons from this, I just study and summarize on this basis

1, Constructor

(1) What is a constructor

Constructor returns the reference of the constructor when creating the instance object. The value of this property is a reference to the function itself, not a string containing the function name

function Person() {}

var p = new Person()

console.log(p.constructor === Person);//true
console.log(p.constructor === Object);//false

The constructor itself is a function, which is no different from ordinary functions, but its initial letter is generally capitalized for specification.

The difference between constructor and ordinary function is that the function of the instance generated by new is the constructor, and the ordinary function is called directly

Does the instance created by an ordinary function necessarily have no constructor attribute? not always

function parent2() {}
var p2 = parent2() //Instances created by normal functions
console.log(p2.constructor);//Error reported, no constructor attribute




function parent3(age) {
    return {
        age : age
    }
}
var p3 = parent3(50)
console.log(p3.constructor);//Object with constructor attribute

(2) Is Symbol a constructor

Symbol is a basic data type, but as a constructor, it is not complete because it does not support the syntax new Symbol(). Chrome does not think it is a constructor. If you want to generate an instance, you can directly use Symbol()

new Symbol(123)//Symbol is not a constructor

Symbol(123)

Although it is a basic data type, the Symbol (123) instance can obtain the constructor attribute value

var sym = Symbol(123)

console.log(sym.constructor);//[Function: Symbol]

Where does the constructor attribute come from?

In fact, it is on the Symbol prototype, that is, the function of Symbol.prototype.constructor to return the instance prototype. The default is the Symbol function

(3) Is the constructor read-only

For reference types, the constructor property value can be changed, but for basic types, it is read-only

Reference type:

function Foo() {//Constructor Foo
    this.value = 42
}


Foo.prototype = {//Prototype object of Foo
    method: function() {}
}

function Bar() {} //Constructor Bar

//Set the prototype property of Bar to the instance object of Foo
Bar.prototype = new Foo() //Here, the direction of Bar.prototype.constructor is changed from Bar() to [Function: Object]
Bar.prototype.foo = "Hello World"


console.log(Bar.prototype.constructor);//[Function: Object]

//Fixed Bar.prototype.constructor to Bar()
Bar.prototype.constructor = Bar//Here, it means that the constructor attribute is modifiable

var test = new Bar()
console.log(test);

Basic types (of course, null and undefined have no constructor):

function Type() {}

var types = [1,"hhh",'true',Symbol(123)]

for(let i = 0; i < types.length; i++) {
    types[i].constructor = Type
    types[i] = [types[i].constructor,types[i] instanceof Type, types[i].toString()]

}

console.log(types.join("\n"));
// function Number() { [native code] },false,1
// function String() { [native code] },false,hhh
// function String() { [native code] },false,true
// function Symbol() { [native code] },false,Symbol(123)

As you can see from the above code, constructors cannot be changed because they are created by read-only native constructors

2, Prototype

javaScript is a prototype based language

Each object has a prototype object. The object takes its prototype as the template and inherits methods and properties from the prototype. These properties and methods are defined on the prototype property of the object constructor function, not the object instance itself

It can be seen from this figure that there is a prototype object Parent.prototype in the Parent object, which has two properties, constructor and__ proto__, Among them__ proto__ Has been deprecated

The constructor Parent has a pointer to the prototype, and the prototype Parent.prototype has a pointer to the constructor Parent.prototype.constructor, as shown in the above figure, which is a circular reference

Assuming p is an instance of the constructor, the relationship between the constructors Parent, Parent.prototype and p is as follows:

__proto__ :  This is an accessor property (i.e getter Function sum setter Function), through which you can access the information inside the object[[Prototype]](An object or null)

[[Prototype]] Is an internal property of an object, which cannot be accessed directly by external code

Note:__ proto__ Properties are standardized in ES6 to ensure the compatibility of Web browsers, but they are not recommended. In addition to standardization, there are performance reasons. For better support, Object.getPrototypeOf() is recommended

If you want to read or modify the [[Prototype]] attribute of an object, the following scheme is recommended. However, setting the [[Prototype]] of an object is still a slow operation. If performance is a problem, you should avoid this operation

//obtain
Object.getPrototypeOf()
Reflect.getPrototypeOf()


//modify
Object.setPrototypeOf()
Reflect.setPrototypeOf()

If you want to create a new object and inherit another object's [[Prototype]], it is recommended to use Object.create()

function Parent() {
    age : 50
}

var p = new Parent()
var child = Object.create(p)

console.log(Object.getPrototypeOf(child));//Parent()
console.log(child.__proto__);//Parent()

The child here is an empty object with a pointer to the object p__ proto__

Optimized implementation of new( Manually implement new, refer to)

As described above, _proto_is not recommended, so we use Object.create() to simulate the implementation. The optimized code is as follows:

function myNew() {
    let Con = [].shift.call(arguments)
    let obj = Object.create(Con.prototype)
    let ret = Con.apply(obj,arguments)
    return ret instanceof Object ? ret : obj
}

3, Prototype chain

Each object has a prototype object, which points to the previous prototype through the _proto _pointer, and inherits methods and properties from it. At the same time, the prototype object may also have a prototype, layer by layer, and finally point to null. This relationship becomes the prototype chain. Through the prototype chain, an object will have properties and methods defined in other objects

function Parent(age) {
    this.age = age
}

var p = new Parent(50)

console.log(p.constructor);//true

Is it known from the above code that there is a constructor attribute in the p instance? No

From this figure, we can see that the instance object itself does not have a constructor attribute, but looks up _ proto _ through the prototype chain, and finally finds the constructor attribute, which points to the Parent

function Parent(age) {
    this.age = age
}

var p = new Parent(50)

console.log(p);//Parent { age: 50 }
console.log(p.__proto__ === Parent.prototype);//true
console.log(p.__proto__.__proto__ === Object.prototype);//true
console.log(p.__proto__.__proto__.__proto__);//null

The following figure shows the operation mechanism of the prototype chain:

4, Summary

1,Symbol Not complete as a constructor because syntax is not supported new Symbol(),But its prototype has constructor Property, i.e Symbol.prototype.constructor. 

2,reference type constructor Property values can be modified, but they are read-only for basic types, of course null and undefined No, constructor Properties.

3,__proto__ Is a property on each instance, prototype Is the property of the constructor, which does not exist on the instance, so the two are different, but p.__proto__ and Parent.prototype Point to the same object.

4,__proto__ Attribute in ES6 It is standardized, but it is not recommended because of performance problems. It is recommended Object.getPrototypeOf(). 

5,Each object has a prototype object through __proto__ The pointer points to the previous prototype and inherits methods and properties from it. At the same time, the prototype object may also have a prototype. In this way, it will eventually point to null,This is the prototype chain

Posted by igorek on Thu, 16 Sep 2021 12:54:21 -0700