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