1. Introduction

Talking about prototypes involves constructors, classes, and so on. I’ll leave that for later extensions. If you’re not clear, look at the extensions first

This article is to find some information (article) after reading the summary, some places may not understand very deep, there are mistakes must help me to point out, thank you very much ~ recently in the “you don’t know Javascript”, after seeing the content of the prototype will be updated ==

2. Prototypes and prototype chains

Before we get started, remember this:

  • object:__proto__andconstructorProperties;
    • __proto__andconstructorobjectUnique.
  • function:prototype,__proto__andconstructorProperties;
    • prototypeisfunctionThe unique;
    • Since functions in JS are also objects, so are functions__proto__andconstructorProperties.
  • All reference types in JS are objectsprototype,__proto__andconstructorProperties;
  • Note:[[Prototype]]and__proto__It’s the same thing: both represent “connections” in the prototype chain. Used in the JavaScript language standard[[prototype]](officially), and__proto__Is provided by many browsers (unofficially);

2.1. The prototypeprototype

  • prototypeisfunctionThe unique;
  • A prototype is an objectThe function prototype.Access;
  • Prototype usually has two properties:__proto__andconstructor;
  • Prototypes can be used to share methods;
  • The reference to this in the prototype is the instance.

2.2. Implicit archetypes__proto__

  • __proto__isobjectThe unique;
  • Object through__proto__To access the parent constructor prototype:Object.__proto__ === parent constructor. Prototype.

2.3. The constructorconstructor

  • constructorisobjectThe unique;
  • Object’s constructor points to the constructor property on the parent constructor stereotype:Constructor === parent constructor. Prototype.constructor.
    • In general, constructor of a constructor prototype refers to the constructor itself, i.e.Constructor === parent constructor. Prototype. constructor === parent constructor(See special casesConstructor can be lost);
    • Note: When there is no constructor property in the parent constructor stereotype, the constructor of the constructor stereotype at the next level up will be found through the stereotype chain (see Constructor may be missing).

Note: Constructor can be lost

function Person(name) {
  this.name = name;
}
Person.prototype = {};

const p = new Person('p');
p.name; // p
Person.prototype; // {} constructor attribute missing!
// constructor of instance p is not a Person!
p.constructor === Person; // false
// Look above Person
p.constructor === Person.prototype.__proto__.constructor // true
Person.prototype.__proto__.constructor === Object // true
p.constructor === Object // true
Copy the code

In the example above, Person. Prototype is assigned to an empty object, and Person itself has no constructor property. Constrctor refers to person.prototype.__proto__. Constructor, which is Object. The constructor property of instance P also points to Object.

Constructor = constructor = constructor

Person.prototype.constructor = Person;
Copy the code

2.4. The prototype chain

We already know about the prototype and the implicit __proto__

An instance that can access the parent constructor’s prototype via __proto__; Prototypes can also be accessed by __proto__ the prototype of the prototype. When you call a method on an instance, you look for that method, starting with the instance itself. If the instance itself does not have one, the parent is searched through __proto__ until it is found. If the destination is found but not found, return NULL.

The chain formed by this search process is the prototype chain.

2.5 summary

(1) For objects:

Object with __proto__ and constructor properties, no prototype:

  • Object.__proto__ === parent constructor. Prototype;
  • Constructor === parent constructor. Prototype.constructor. In general,Prototype. constructor === parent constructor;

(2) For the function:

  • Prototype takes two arguments: constructor and __proto__ :

    • Constructor === parent constructor. Prototype.constructor. In general,Prototype. constructor === parent constructor;
    • Constructor. Prototype. __proto__ === parent constructor(e.g.,Date.prototype.__proto__ === Object.prototype)
  • Functions are objects, so they also have __proto__ and constructor attributes, the same as (1);

  • Note: the constructor.prototype.__proto__ is different from the constructor.__proto__. Such as:

      Date.prototype.__proto__ === Object.prototype; //true
      Date.prototype is an object; And the parent constructor of an Object is Object.
      Date.__proto__ === Function.prototype; // true
      // Since Date itself is a constructor, its parent constructor is Function.
    Copy the code

3) The top level of the scope chain is null.

3. Prototype chain diagram

Let’s look at a simple chestnut:

function Father() {};
const son = new Father();
Copy the code

Prototype, __proto__, constructor Let’s draw together

Step 1: Prototype

There is a constructor, Father, whose prototype is accessible through father.protorype.

Step 2: Instance instance

  • The instance isnewOut of theobject, so the instance owns__proto__andconstructorTwo attributes;
  • Instance objectsThere is noprototypeAttributes as well! (Instance method ==)

An instance object son is created using the new operator.

// Follow the chestnuts above

// The instance object has no Prototype property
son.prototype === undefined; // true

// Prototype (Father is an instance of Function)Father.prototype ! = =undefined; // true
Father.__proto__ === Function.prototype; // true
Copy the code

Step 3:__proto__

The instance’s __proto__ attribute points to the parent constructor’s prototype: father. prototype === son.__proto__

Step 4: Constructor

Step 5: Father’s members

The link between son, Father, Function and Object looks like this: (I suggest you look at the black line first, then look at the bright one)

self-test

Now that we have drawn the prototype chain diagram, the following judgments will be easy for you

// The object's __proto__ refers to the parent's prototype
son.__proto__ === Father.prototype; // true
// The constructor of an object points to its parent constructor
son.constructor === Father; // true
Constructor refers to the constructor itself, so the constructor of an instance object also refers to: constructor
son.constructor === Father.prototype.constructor; // true

// constructor refers to itself
Father.prototype.constructor === Father; // true
// Prototype is an Object whose parent is Object, so father.prototype.__proto__ refers to object.prototype
Father.prototype.__proto__ === Object.prototype; // true
// The parent of the constructor Father is Function, so Father.__proto__ refers to function. prototype
Father.__proto__ === Function.prototype; // true
// The constructor of a constructor is its parent function, so...
Father.constructor === Function; // true
/ / 1) constructor. The prototype. The constructor to the constructor itself, so the Function. The prototype. The constructor = = = Function; Function. Constructor == Function. Constructor == Function. 3) So they are equal
Father.constructor === Function.prototype.constructor; // true

// Function is itself an instance of its parent constructor. This is because: construction.prototype.constructor refers to the constructor itself
Function.prototype.constructor === Function; // true
// Function. Prototype is an Object, so...
Function.prototype.__proto__ === Object.prototype; // true
// Function is itself an instance of its parent constructor, but its parent constructor is still Function, so...
Function.__proto__ === Function.prototype; // true
// Function.__proto__ refers to Function
Function.__proto__.prototype === undefined; // true
// function.__proto__ ();
Function.__proto__.constructor === Function; // true
// Function.__proto__ is an instance of Function.
Function.__proto__.__proto__ === Object.prototype; // true
// Function.__proto__.__proto__.
Function.__proto__.__proto__.constructor === Object; //true
// function.__proto__.__proto__ refers to object. prototype
Function.__proto__.__proto__.__proto__ === null; //true

// Object is also a constructor. Prototype. constructor refers to the constructor itself
Object.prototype.constructor === Object; // true
// The level above object.prototype is the end of the prototype chain, which is null
Object.prototype.__proto__ === null; // true
// Object is also an instance of its parent constructor, so object.__proto__ refers to function.prototype
Object.__proto__ === Function.prototype; // true
// Object.__proto__ refers to its parent constructor
Object.__proto__.__proto__ === Object.prototype; // true
// Object.__proto__ refers to its parent constructor.
Object.__proto__.constructor === Function; // true
// 1) Object.__proto__ refers to the parent constructor. 2) Object. __proto__ refers to object. prototype; 3) object.prototype. __proto__ is null
Object.__proto__.__proto__.__proto__ === null; // true
Copy the code

4. Develop

4.1. Constructors

  • A constructor looks like a normal function, but it creates objects with the new keyword;
  • In general, public properties are defined in constructors, and public methods are placed on prototype objects (methods on the prototype are shared by the instance).

4.1.1. Instance and static members

  • Instance members:
    • Inside the constructor, the member added by this;
    • It can only be accessed through an instantiated object.
  • Static members:
    • Members added to the constructor itself;
    • It is accessible only through the constructor.
function Person(name, age) {
  // Instance members
  this.name = name;
  this.age = age;
}

// Static members
Person.sex = 'woman';

const p1 = new Person('LaoHuang'.24);
console.log(p1.name); // 'LaoHuang'
console.log(p1.age); / / 24
console.log(p1.sex); // undefined (instance cannot access static members of constructor)

console.log(Person.name); // Person undefined (constructor cannot directly access instance member, must be instantiated to access)
console.log(Person.sex); // female (the constructor can access its static members)
Copy the code

4.1.2. New an instance

This process is called instantiation.

function Person(name) {
  this.name = name;
}

const p1 = new Person('LaoHuang');
console.log(p1) // Person {name: "LaoHuang"}
Copy the code

P1 is an instance object. The process of creating a new object consists of the following steps:

  • Create an empty object p1:{};
  • Prepare the prototype chain link for P1:p1.__protp__ = Person.prototype;
  • Bind this to make the constructor’s this point to the new object p1:Person.call(this);
  • Assign values to properties of the new object:p1.name;
  • Return to this:return this. The new object now has the methods and properties of the constructor.

4.1.3. Methods for sharing instances

Methods added to the constructor prototype are shared by the instance.

function Person(name) {
  this.name = name;
}
Person.prototype.getName = function() {
  console.log('Name:' + this.name);
}

const p1 = new Person('LaoHuang');
const p2 = new Person('FeiFei');
p1.getName(); // Name: LaoHuang
p2.getName(); // Name: FeiFei
console.log(p1.getName === p2.getName); // true
Copy the code

4.2 Class Class

  • The essence of a class is still a function, which is just another way of writing a constructor;

  • Classes have no variable promotion and must be defined before they can be instantiated.

  • The constructor method is the default method of the class and is automatically called when an object instance is generated with the new command. A class must have a constructor method. If not explicitly defined, an empty constructor method will be added by default.

  • All methods of a class are defined on its prototype:

    class Person {
      constructor(name) {
        this.name = name;
      }
      getName() {
        console.log('Name:' + this.name); }}const p1 = new Person('LaoHuang');
    const p2 = new Person('FeiFei');
    p1.getName(); // Name: LaoHuang
    p2.getName(); // Name: FeiFei
    console.log(p1.getName === p2.getName); // true
    Copy the code

4.2.1. How do I add methods to a class

Use the Object. The assign ().

class Person {
  constructor(name, sex) {
    this.name = name;
    this.sex = sex;
  }
  getName() {
    console.log('Name:' + this.name); }}Object.assign(Person.prototype, {
  getSex(){
    console.log(this.name + The gender of 'is:' + this.sex)
  }
});

const p1 = new Person('LaoHuang'.'woman');
const p2 = new Person('FeiFei'.'male');
p1.getSex(); // The gender of LaoHuang is female
p2.getSex(); // The gender of FeiFei is male
console.log(p1.getSex === p2.getSex); // true
Copy the code

4.3. Differences between classes and constructors

  • Class must be called with new, otherwise an error will be reported. This is a major difference from normal constructors, which can be executed without new;
  • All instances of a class share a prototype object;
  • Class, the default is strict mode, so you do not need to useuse strictSpecify the running mode.

4.4. Inheritance

I’m not going to expand on inheritance here, just prototype-related. Try drawing a prototype

4.4.1. Constructors + prototype objects

function Person(name) {
  this.name = name;
}
Person.prototype.getName = function () {
  console.log('Name:' + this.name);
};
function Girl(name, sex) {
  When instantiated, this in Person points to the current instance
  Person.call(this, name);
  this.sex = sex;
}
// Girl.prototype = Person.prototype; // In this way, adding a prototype method to a subclass will also affect the superclass
Girl.prototype = new Person();
Girl.prototype.sing = function () {
    console.log('I am singing');
};
let g1 = new Girl('little red'.'woman');
console.log(Person.prototype); // {getName: logon, constructor: logon}
console.log(Girl.prototype); // Person {name: undefined, sing: logon}
Copy the code

Its prototype chain diagram looks like this:

As you can see from this picture:

/ / 1) g1. Point constructor Girl. Prototype. The constructor
/ / 2) and Girl. The prototype is the Person instance, and the Girl. The prototype. The constructor is equivalent to (new Person) constructor, namely Person. The prototype. The constructor, The Person itself
g1.constructor === Person; //true
Copy the code

Consider this: what if you want g1.constructor === Girl?

4.4.2. Extends sugar

(1) Super:

Super can be used as a function and an object:

  • When used as a function, it can only be used in the constructor of a subclass, representing the constructor of the superclass, butsuperIn thethisRefers to an instance of a subclass, so in a subclasssuper()Represents theParent.prototype.constructor.call(this).
  • When used as an object,superRepresents a superclass prototype object, i.eParent.prototype.

(2) What extends does:

  • Step 1: Inherit the prototype of the parent class, will subclass__proto__Pointing to the superclass itself;
  • The second step, call inheritance, is the processing of super(). Inherits object methods from the parent class to the child class object; This is why it is necessary to add super() to es6 inheritance, because you cannot inherit from the object properties of the parent class.
  • Step 3: Create subclasses of their own methods.
class Person {
  constructor(name){
    this.name = name;
  }
  getName(){
    return this.name; }}class Girl extends Person{
  constructor(name, sex){
    super(name);
    this.sex = sex;
  }
  getSex(){
    return this.getName() + 'gender:' + this.sex; }}const g1 = new Girl('little red'.'woman');
console.log(g1.getSex()); // Xiao Hong's gender: female
Copy the code

Its prototype chain diagram looks like this (remember to compare with the first inheritance) :

As you can see from this picture:

// This is where extends is special
Girl.__proto__ === Person; //true
Copy the code

Reference 5.

  • 2020 Interview Harvest – JS prototype and prototype chain
  • Diagram prototypes and prototype chains
  • MDN – Object prototype