preface

Take a look at the documentation, learn about prototypes and prototype chains, and learn about prototypes from a specification perspective

  1. What is the definition of a prototype?
  2. What is a prototype chain?
  3. Function hasprototypeAttributes?
  4. 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:

  1. Constructors all have oneprototypeProperties,prototypeProperty refers to an object that was created by calling the constructorThe instanceThe prototype of the
  2. Object implicit referenceconstructor.prototypeThat 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.
  3. All properties on the stereotype object are accessible to instance objects that own the stereotype object

Let’s look at two more special properties:

  1. constructor, pointing to the corresponding constructor
  2. 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:

  1. A function object is a support[[Call]]The object of the inner method.
  2. A constructor is a support[[Construct]]The object of the inner method.
  3. To achieve the[[Construct]]Internal method objects must be supported[[Call]]Internal methods, then each constructor is a function object
  4. So, oneconstructorAlso 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:

  1. The first step, two, is to assert, which is what I mean by affirmationsconstructExprisNewExpressionorMemberExpressionTo determine whether the argument is empty or has an argument.
  2. Step 3 and step 4 passconstructExprThe expression finds the corresponding constructorconstructor
  3. Steps 5 and 6 deal with the parameters
  4. Step 7: JudgeconstructorIf it is a constructor, then an error is reported[[Construct]]The implementation.
  5. Step 8 returnsConstruct(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.

  1. Look at step 5, which results in creating a prototype forF.prototypeThe object,newTargetIt’s a pointing functionFA reference to the
  2. Move to step 8, which simply translates to changethisPoint to, actually there’s a lot of stuff going on inside of the execution context that I’m not sure about
  3. Look at step 11, which is simply interpreted as parsing the code inside the constructor to get the result of the parsing
  4. And then steps 13 and 14,If result.[[Type]] is returnIn this case, the way I understand it is to determine whether the function is aheadreturnThat is, whether or not they wrote itreturnIf not earlierreturnIf yes, return the result directly.
  5. 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:

  1. Creates an empty object as an instance of the object to be returned.
  2. Point the empty object’s prototype to the constructor’sprototypeProperties.
  3. Assigns this empty object to the internalthisThe keyword.
  4. 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

  1. The Class declaration is essentially a function
  2. The prototype of this class is really the prototype of the instance
  3. Inheritance is the creation of a child class’s prototype from a parent class’s prototype