preface
Take a look at the documentation, learn about prototypes and prototype chains, and learn about prototypes from a specification perspective
- What is the definition of a prototype?
- What is a prototype chain?
- Function has
prototype
Attributes? - What happened to New?
Definition of a prototype
ECM-262 : object that provides shared properties for other objects
An object that provides shared properties for other objects
Here’s another statement from ECM-262 about prototypes:
When a constructor creates an object, that object implicitly references the constructor’s “prototype” property for the purpose of resolving property references. The constructor’s “prototype” property can be referenced by the program expression
constructor.prototype
, and properties added to an object’s prototype are shared, through inheritance, by all objects sharing the prototype.Alternatively, a new object may be created with an explicitly specified prototype by using the
Object.create
built-in function.Translation:
When the constructor creates an object, the object implicitly refers to the constructor’s “prototype” property in order to parse the property references.
Constructor’s “prototype” property can be referenced by the programmatic expression constructive.prototype, and by inheritance, properties added to an object prototype are shared by all objects that share that prototype.
Alternatively, you can create a new Object by explicitly specifying a prototype by calling the built-in function Object.create
Relationships between stereotypes, constructors, and instance objects
So from the above description we know the following:
- Constructors all have one
prototype
Properties,prototype
Property refers to an object that was created by calling the constructorThe instanceThe prototype of the - Object implicit reference
constructor.prototype
That is, there is a pointer to our power object[[prototype]]
Point to this prototype object, but this pointer[[prototype]]
We can’t see it, but a browser does__proto__
Properties. - All properties on the stereotype object are accessible to instance objects that own the stereotype object
Let’s look at two more special properties:
constructor
, pointing to the corresponding constructor- This is a property that every JavaScript object (except null) has, called
__proto__
, which points to the object’s prototype.
So the relationship between the prototype, constructor, and instance object is shown below
Prototype chain
A prototype is essentially an object, so does a prototype have a prototype? The answer is yes. A prototype is a prototype. So, based on the diagram above, we can infer the relationship between a prototype.
It doesn’t have to be two, it can be multiple. So what exactly is a prototype chain? The prototype chain is essentially the part of the diagram above with the constructor removed.
Prototype properties can be shared, so my bottom instance Object has access to person. prototype properties, and Person.prototype has access to Object.prototype properties. So this is true
person1.a === Person.prototype.a === Object.prototype.a
Copy the code
Then to access the property of an Object, first look up the property in the Object itself. If you do not look up the property in the prototype Object, you have not looked up the property until object. prototype.
Hand write instanceof
The instanceof operator is used to check whether the constructor’s prototype property appears on the prototype chain of an instance object.
Let’s write it by hand using the prototype chain principle
function myInstanceOf(obj, constructor) {
if ((typeofobj ! = ='object' && typeofobj ! = ='function') || obj === null) {
return false
}
const proto = Object.getPrototypeOf(obj)
if (proto === constructor.prototype) { // use the constructor
return true
} else {
return myInstanceOf(proto, constructor)}}console.log(myInstanceOf([], Array)) / /true
console.log(myInstanceOf(false.Array)) / /true
Copy the code
Functions and constructors (do functions have a ‘prototype’ attribute?)
Do functions have a ‘ ‘prototype’ attribute?
Let’s look at an explanation of the ecM-262 constructor
function object that creates and initializes objects.
The value of a constructor’s “prototype” property is a prototype object that is used to implement inheritance and shared properties.
Translation:
The function object that creates and initializes the object.
The value of the constructor’s “prototype” property is a prototype object used to implement inherited and shared properties.
As if a constructor is a function, but what’s the difference? Let’s look at another passage from the text
A function object is an object that supports the [[Call]] internal method.
A constructor is an object that supports the [[Construct]] internal method.
Every object that supports [[Construct]] must support [[Call]]; that is, every constructor must be a function object.
Therefore, a constructor may also be referred to as a constructor function or constructor function object.
Let’s take a look at this:
- A function object is a support
[[Call]]
The object of the inner method. - A constructor is a support
[[Construct]]
The object of the inner method. - To achieve the
[[Construct]]
Internal method objects must be supported[[Call]]
Internal methods, then each constructor is a function object - So, one
constructor
Also called constructors or constructor objects
Now it’s clear how functions and constructors are related. The key is whether or not the [[Construct]] inner method is implemented. So what is [[Construct]] responsible for? It creates an object by calling new and super.
** So back to the above question, the constructor must have a ‘ ‘prototype’ attribute, but do all other functions have it? ** Let’s write some code to test it
function fn() {}
const arrowFn = () = > {}
class classFn {}
function* genFn() {}
async function asyncFn() {}
async function* asyncGenFn() {}
console.log(fn.hasOwnProperty('prototype')) // true
console.log(arrowFn.hasOwnProperty('prototype')) // false
console.log(classFn.hasOwnProperty('prototype')) // true
console.log(genFn.hasOwnProperty('prototype')) // true
console.log(asyncFn.hasOwnProperty('prototype')) // false
console.log(asyncGenFn.hasOwnProperty('prototype')) // true
Copy the code
The [[Construct]] ‘inner method is not implemented (😂).
For us, just remember that our function fn() {} function can be used as a constructor.
What happened to New
What happened to New? What does he do? Here we go. What does his spec say
I do not know the specific definition of NewExpression and MemberExpression. According to my understanding, NewExpression should be an expression in the form of New F, while MemberExpression should be New F (ARgs).
Form of the call.
We are looking at the process and results of EvaluateNew:
- The first step, two, is to assert, which is what I mean by affirmations
constructExpr
isNewExpression
orMemberExpression
To determine whether the argument is empty or has an argument. - Step 3 and step 4 pass
constructExpr
The expression finds the corresponding constructorconstructor
- Steps 5 and 6 deal with the parameters
- Step 7: Judge
constructor
If it is a constructor, then an error is reported[[Construct]]
The implementation. - Step 8 returns
Construct(constructor, argList)
Call result of
The core is the Construct(constructor, argList) step. What is it? Construct is the implementation of [[Construct]] internal methods. Let’s see what he’s doing
I’m a little confused when I see this. What is this? Take your time and block out what you don’t understand.
- Look at step 5, which results in creating a prototype for
F.prototype
The object,newTarget
It’s a pointing functionF
A reference to the - Move to step 8, which simply translates to change
this
Point to, actually there’s a lot of stuff going on inside of the execution context that I’m not sure about - Look at step 11, which is simply interpreted as parsing the code inside the constructor to get the result of the parsing
- And then steps 13 and 14,
If result.[[Type]] is return
In this case, the way I understand it is to determine whether the function is aheadreturn
That is, whether or not they wrote itreturn
If not earlierreturn
If yes, return the result directly. - Let’s see what we did in step 13. The important thing is that 13.
If kind is base
, returns the previously created object.
So this fits our normal understanding:
- Creates an empty object as an instance of the object to be returned.
- Point the empty object’s prototype to the constructor’s
prototype
Properties. - Assigns this empty object to the internal
this
The keyword. - Start executing the code inside the constructor.
But it all depends on If kind is the base of this, then this kind is what, see step 4 in the picture below, it is a function of the built-in properties [[ConstructorKind]], the internal attribute has two values: base | derived and used to judge whether the derived class constructor.
So here we know that the normal constructor new would take the form above. Derived class constructors, however, are different.
Write the normal constructor by handnew
We know the process so let’s write it by hand
function myNew(fn, ... args) {
const obj = Object.create(fn.prototype)
fn.apply(obj, args)
return obj
}
function Test(a, b) {
this.a = a
this.b = b
this.c = 'test'
}
Test.prototype.say = function () {
console.log(this.a, this.b, this.c)
}
const obj = new Test(1.2)
const obj1 = myNew(Test, 1.2)
console.log('obj :>> ', obj) // obj :>> Test {a: 1, b: 2, c: "test"}
console.log('obj1 :>> ', obj1) // obj1 :>> Test {a: 1, b: 2, c: "test"}
obj.say() // 1 2 "test"
obj1.say() // 1 2 "test"
Copy the code
About the inheritance
For more information on inheritance, see the big guy’s article on the various ways JavaScript can delve into inheritance, as well as the pros and cons
Let’s do a little experiment with Class
Class is a syntactic sugar of archetypal inheritance, everyone agrees. What is Class? Let’s do a couple of little experiments
class MyClass {
constructor() {
this.a = 1
}
say() {
console.log('hi')}}class MyChildClass extends MyClass {
constructor() {
super(a)this.b = 2
}
say() {
console.log('hi Child')}}const myInstance = new MyClass()
const myChildInstance = new MyChildClass()
console.log(Object.prototype.toString.call(MyClass)) // [object Function]
console.log(MyClass.hasOwnProperty('prototype')) // true
console.log(myInstance) // {a:1}
console.log(Object.getPrototypeOf(myInstance) === MyClass.prototype) // true
MyClass.prototype.say() // hi
console.log(myChildInstance) // { a: 1, b: 2 }
console.log(Object.getPrototypeOf(MyChildClass.prototype) === MyClass.prototype) // true
MyChildClass.prototype.say() // hi Child
Object.getPrototypeOf(MyChildClass.prototype).say() // hi
Copy the code
You can see that in the code above
- The Class declaration is essentially a function
- The prototype of this class is really the prototype of the instance
- Inheritance is the creation of a child class’s prototype from a parent class’s prototype