In-depth analysis of prototypes
Review the writing of the prototype pattern
function Person(){}
Person.prototype.name = 'test';
Person.prototype.sayName = function(){
console.log(this.name);
};
let person1 = new Person();
let person2 = new Person();
person1.sayName = () = >{}
person1.sayName(); // "test"
person2.sayName(); // "test"
console.log(person1.sayName === person2.sayName); // true
Copy the code
Every time a function is created, a new object is created
Whenever a function is created, a Prototype attribute (pointing to the prototype object) is created for that function according to certain rules
Person.prototype points to the prototype object
By default, all stereotype objects automatically get a property called constructor that refers back to the constructor associated with them.
console.log(Person.prototype.constructor == Person) // true
Copy the code
Each time an instance of the constructor is created by calling new, the [[Prototype]] pointer inside it is assigned to the constructor’s Prototype object. In the browser we can get the prototype object from the __proto__ property of the instance.
(There is no standard way to get the [[Prototype]] feature in scripts, but the browser exposes the __proto__ attribute on an object, which can be used to access the object’s Prototype in code.)
console.log(Person.prototype === person1.__proto__) // true
Copy the code
Implicit and explicit archetypes
We often call the stereotype pointer of an instance an implicit stereotype and the stereotype pointer of a function an explicit stereotype.
These two Pointers point to the same prototype object, only the pointer names are different.
The key to understand is this:
There is a direct relationship between the instance and the constructor stereotype, but not between the instance and the constructor. Simply put, there is no constructor pointer to the instance’s own property that points to the constructor.
console.log(person1.hasOwnProperty('constructor')) // false
Copy the code
So to sum up:
Constructor, prototype object, and instance are different objects. The constructor creates and associates a prototype object with the new constructor. The constructor gets the prototype by pointer to prototype, and the instance gets the prototype by __proto__.
Instances are only directly related to prototype objects.
Prototype chain
An object has an implicit stereotype pointer to a stereotype object.
A prototype object is also an object, so it is looped until the end is null, and a chain is formed.
console.log(person1.__proto__.__proto__.__proto__) // null
Copy the code
Here’s another example of a full view of the prototype chain
function A(){}
let a = new A()
function B(){}
// let B be called the constructor of a instance object
B.prototype = a
let b = new B()
// Then the prototype chain of b is b.__proto__
console.log(b.__proto__ === B.prototype&&
b.__proto__.__proto__ == A.prototype &&
b.__proto__.__proto__.__proto__ === Object.prototype &&
b.__proto__.__proto__.__proto__.__proto__ === null) // true
Copy the code
That is, every object has a chain of implicit stereotypes that starts with null stereotypes and ends with null stereotypes. Object. Prototype = null;
Property access rules
When an object accesses a property, it looks in its own property. If it can’t find one, it looks in its prototype chain. If it finds one, it returns.
Person1.sayname is found in person1.__proto__.
console.log(person1.sayName === person1.__proto__.sayName) // true
Copy the code
Properties can be obtained from prototypes, but can they be modified directly from examples?
While an instance can get a value on a prototype object, it cannot be overridden.
Assignment is simply equivalent to adding an attribute of the same name as the prototype object to the instance itself, creating a “masking” effect. Such as:
person1.sayName() // 'test'
person1.sayName = () = >console.log('rewrite');
person1.__proto__.sayName() // 'test'
person1.sayName() // 'override'
Copy the code
How do I remove stereotype attributes after they are “Shadowed”
Delete the instance’s own attributes using the DELETE operator
delete person1.sayName
person1.sayName() // 'test'
Copy the code
The way you get your own and stereotype attributes
HasOwnPropertype and in, the former is judgment own and the latter is judgment own and stereotype enumerable
Combine existing capabilities to implement a function that can only enumerate stereotypes.
function hasProtoProperty(obj,name){
return! obj.hasOwnProperty(name)&& (namein obj)
}
Copy the code
Properties that can only be enumerated
Self with the prototype
for in
Only their own
Object.keys
Only a prototype
Use the above custom hasProtoProperty
All the properties
Own property only
Use the static method of Object.
Object. GetOwnPropertyNames () for the attribute named character.
Object. GetOwnPropertySymbols () called Symbol for attributes.
Attribute enumeration order
The order of the for in loop, object.keys () enumeration is indeterminate, depends on the JS engine and varies from browser to browser.
Object. GetOwnPropertyNames (), Object. GetOwnPropertySymols (), the Object, the assign () is a sequence.
The order rules: numeric keys are first in ascending order, then characters and symbolic keys are both literals and insertions in first-come-last order.
let o = {
2:2.jim:'jim'.1:1.tony:'tony'
};
o['lily'] = 'lily';
console.log(o) // {1: 1, 2: 2, jim: 'jim', tony: 'tony', lily: 'lily'}
Copy the code
Dig deeper into constructors
Let’s review how constructors are written
function CreatePerson(name){
this.name = name;
this.toDo = function(){
console.log(this.name); }}let person1 = new CreatePerson('test')
Copy the code
Constructors are also functions
The only difference between a constructor and a normal function is how it is called. Any function that calls with the new operator is a constructor.
What’s different about constructors creating objects
First, constructors are written in the shadow of the factory pattern, but the constructor pattern has some key changes in comparison:
- Objects are not explicitly created, but instead are used
this
- Properties and methods are directly assigned to this
this
- Remove the
return
But the way it’s called has changednew
The call.
So that’s the standard way.
Constructors start with a capital letter
One detail is that constructors have uppercase names. This is the convention: constructors should always start with uppercase names. There is no real difference between constructors and functions.
Using thenew
The way you call the constructor, what you’re secretly doing
- Create a new object in memory called “little New”
- Internal of the new object “little New”
[[prototype]]
Features thatImplicit stereotypeThe partners assigned to the constructor are the function’sExplicit prototypeprototype
This behavior is simply ownership: the new object “shin” recognizes the constructor’s partner as its creator. - Inside the constructor
this
I’m pointing to this new object, shin. - This completes the execution of the code inside the function.
- If the constructor does not return, or returns an empty value, the new object is returned. (If a non-null value is returned, the new object “new” is forcibly returned instead and the ability to identify the object is lost).
So the new object created by the constructor is this little new object.
Resolved the problem of resolving object identification in factory mode
Constructor can judge its own type by judging the value of the instance’s constructor.
console.log(person1.constructor === createPerson) // true
Copy the code
We should actually make it clear that constructor is an attribute of the stereotype.
console.log(person1.hasOwnProperty('constructor')) // false
console.log(person1.__proto__.constructor === createPerson) // true
Copy the code
But there is the possibility of tampering with constructor,
person1.__proto__.constructor = () = >{}
console.log(person1.constructor === createPerson) // false
Copy the code
So it’s not very reliable
The instanceof operator
Usage is:
console.log(person1 instanceof createPerson) // true
Copy the code
The left side of the instanceof operator is an instance object and the right side is a constructor.
How do you understand that?
Recall the prototype chain: then any object has a prototype chain that starts with an implicit prototype and ends with null.
Then combining the prototype chain can be understood as:
Object’s stereotype chain has an object that is an explicit stereotype of this constructor
function A(){}
let a = new A()
function B(){}
// let B be called the constructor of a instance object
B.prototype = a
let b = new B()
// Then the prototype chain of b is b.__proto__
console.log(b.__proto__ === B.prototype&&
b.__proto__.__proto__ == A.prototype &&
b.__proto__.__proto__.__proto__ === Object.prototype &&
b.__proto__.__proto__.__proto__.__proto__ === null) // true
console.log(b instanceof B) // true
console.log(b instanceof A) // true
console.log(b instanceof Object) // true
Copy the code