Prototype and prototype chain
Let’s look at the relationship between constructors, instances, and prototype objects
“There is a direct connection between the instance and the prototype object, but not between the instance and the constructor.”
Two concepts
Js is divided into “function objects” and “normal objects”. Each object has a __proto__ attribute, but only function objects and “non-arrow functions” have a Prototype attribute.
- attribute
__proto__
Is an object [instance through__proto__
Implicit archetype refers to its prototype object, which has two properties,constructor
and__proto__
; - The prototype object has a default
constructor
Property to record which constructor the instance was created by;
The prototype
To understand the prototype
When you create a function (a non-arrow function), you create a Prototype property (pointing to the prototype object) for that function according to specific rules. By default, all stereotype objects automatically get a property called constructor that refers back to the constructor associated with them. When you customize a constructor, the stereotype Object acquires only the constructor attribute by default; all other methods inherit from Object. Each time the constructor is called to create a new instance, the inner [[Prototype]] pointer of that instance is assigned to the constructor’s Prototype object. There is no standard way to access the [[Prototype]] feature in scripts, but Firefox, Safari, and Chrome expose the __proto__ property on each object, which allows access to the Prototype of the object.
Person.prototype.name = "Nicholas"; person.prototype. name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function() { console.log(this.name); }; Let person1 = new Person() let person2 = new Person() Constructors have a prototype Object associated with the console. The log (Object. The prototype. ToString. Call (Person. The prototype)) / / [Object Object] console.log(Person.prototype) // {constructor: ƒ} // The constructor has a prototype attribute referencing its prototype object, which in turn has a constructor attribute referencing the constructor. In other words, Circular reference between the console. The log (Person) prototype) constructor = = = Person); // true // The constructor, prototype object, and instance are three completely different objects console.log(person1! == Person); // true console.log(person1 ! == Person.prototype); // true console.log(Person.prototype ! == Person); // true // Instance is linked to the Prototype object by __proto__, which actually points to the hidden property [[Prototype]] // Constructor is linked to the Prototype object by the Prototype property. Instances are not directly linked to the constructor, but directly to the Prototype object. Console. log(person1.__proto__ === person.prototype); // true conosle.log(person1.__proto__.constructor === Person); // true // Two instances of the same constructor that share the same prototype object console.log(person1.__proto__ === person2.__proto__); // true // object.getProtoTypeof (), returns the value of the internal property of the parameter [[Prototype]], used to get the Prototype Object, Console. log(object.getPrototypeof (person1) == person.prototype); // trueCopy the code
The diagram below:
Person. The prototype to the prototype object, and the Person. The prototype. Its constructor refers back to the Person the constructor. The prototype object contains the Constructor attribute and other attributes added later. Person1 and person2, two instances of Person, each have only one internal attribute that refers back to Person.prototype, and neither has a direct connection to the constructor.
Prototype level
When a property is accessed through an object, a search is initiated by the name of the property. The search begins with the object instance itself. If a given name is found on this instance, the value of that name is returned. If the property is not found, the search follows the pointer into the prototype object, and when the property is found on the prototype object, the corresponding value is returned. Therefore, when person1.sayName() is called, a two-step search occurs. First, the JavaScript engine asks, “Does the Person1 instance have the sayName attribute?” The answer is no. Then, go ahead and ask, “Does the prototype for Person1 have the sayName attribute?” The answer is yes. The function saved on the prototype is returned. When person2.sayname () is called, the same search process occurs and the same results are returned. This is how stereotypes are used to share properties and methods across multiple object instances.
Prototype chain
Review the relationship between constructors, stereotypes, and instances: each constructor has a Prototype pointing to the prototype object, the prototype object has a constructor property pointing back to the constructor, and the instance has an internal pointer to the prototype. What if the stereotype is an instance of another type? That means that the stereotype itself has an internal pointer to another stereotype, which in turn has a pointer to another constructor. This creates a chain of stereotypes between the instance and the stereotype. This is the basic idea of a prototype chain.
function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = function () { return this.property; }; function SubType() { this.subproperty = false; } // SuperType subtype. prototype = new SuperType(); SubType.prototype.getSubValue = function () { return this.subproperty; }; let instance = new SubType(); console.log(instance.getSuperValue()); // trueCopy the code
The types SuperType and SubType define an attribute and a method, respectively. The main difference between the two types is that SubType inherits from SuperType by creating an instance of SuperType and assigning it to its own prototype subtType. prototype. This assignment overrides the original prototype of SubType, replacing it with an instance of SuperType. This means that all properties and methods accessible to SuperType instances will also exist in SubType.prototype. After this inheritance, the code immediately adds a new method to subType. prototype, the SuperType instance. Finally, an instance of SubType is created and its inherited getSuperValue() method is called.
Simulation of the new
What happens when YOU use new?
- Creates an empty object as an instance of the object to be returned
- Points the empty object’s prototype to the constructor’s
prototype
attribute - Assigns this empty object to the internal
this
The keyword - Start executing the code inside the constructor
- If the constructor returns an object, the object is returned directly, otherwise the created object is returned
That is, inside the constructor, this refers to a newly generated empty object on which all operations will be performed. A constructor is called a “constructor” because its purpose is to manipulate an empty object (this object) and “construct” it into what it needs to look like.
function simulateNew() { let newObject = null,result = null, Constructor = Array. The prototype. The shift. The call (the arguments) / / parameter to judge the if (typeof constructor! Error ('type error') return} // Create an empty object, NewObject = object.create (constructive.prototype) // point this to a newObject, Result = constructive. apply(newObject, Judging the arguments) / / return objects const flag = result && (typeof result = = = 'object' | | typeof result = = = 'function') / / returns the result return flag ? result : */ function Person(name) {this.name = name} const p1 = new Person("p1") const p2 = simulateNew(Person, 'p2') console.log("p1",p1, p1 instanceof Person); console.log('p2', p2, p2 instanceof Person)Copy the code
Simulation instanceof
The main implementation principle of Instanceof is “as long as the right variable’s” prototype “is on the left variable’s prototype chain.” Thus, instanceof iterates through the prototype chain of the left variable until it finds the prototype of the right variable. If the lookup fails, it returns false, telling us that the left variable is not an instanceof the right variable.
function instanceOf(leftVaule, rightVaule) { let rightProto = rightVaule.prototype; // Take the prototype value of the right expression leftVaule = leftvaule.__proto__; While (true) {if (leftVaule === null) {return false; } if (leftVaule === rightProto) { return true; } leftVaule = leftVaule.__proto__ } }Copy the code