Note: today went to the interview, the interviewer asked a lot of implementation advantages and disadvantages, so reorganize the article. Now it’s easier to understand.

Pre-knowledge – instances, constructors, stereotype chain relationships

// ConstructorFunc
function ConstructorFunc() {}// Instance: instance
let instance = new ConstructFunc()
Copy the code
  • __proto__Implicit stereotype
  • prototypeAccording to the prototype

Instance and constructor

instance.__proto__ === ConstructFunc.prototype // true 
Copy the code

Constructors relate to Object objects

ConstructFunc.prototype.__proto__ === Object.prototype // true
// Special note
Object.prototype.__proto__ === null // true
Copy the code

Constructors relate to Function objects

ConstructFunc.__proto__ === Function.prototype // true
// Special note
Function.prototype.__proto__ === Object.prototype // true
Copy the code

What does the new operator do

New operator -MDN

The new keyword does the following:
  1. Create an empty simple JavaScript object (that is {});
  2. Linking this object (setting its constructor) to another object;
  3. Use the new object created in Step 1 as the context for this;
  4. If the function does not return an object, this is returned.

Maybe the second and fourth steps are not very clear to you. Here are the four steps:

function User(name) {
    this.name = name;
}
let u = new User('vien');
Copy the code
  1. Create an empty objectu = {}
  2. Binding prototype,u.__proto__ = User.prototype
  3. Call the User() function and pass the empty object u as this, i.eUser.call(u)
  4. If the User() function completes its own return of type object, return this; otherwise return this. Note that if the constructor returns a primitive value, this is still returned

inheritance

Note: Do not modify properties or methods on the display stereotype

The instance looks for properties or methods along the implicit prototype instance.__proto__ === child.prototype child.prototype.__proto__ === parent.prototype

ECMAScript only supports implementation inheritance, and its implementation inheritance relies primarily on prototype chains.

Prototype chain inheritance

Principle: The prototype chain inheritance method is implemented by using the prototype of Javascript. In Javascript, any function has two properties: prototype and __proto__, and every object has a __proto__ attribute. The value of the __proto__ attribute in the object is derived from the prototype attribute of the function that constructed the object. From prototype and __proto__, we construct the prototype chain, and then use the prototype chain to implement inheritance.

// Prototype chain inheritance
/ / parent class
function Parent() {
    this.name = 'vien';
    this.hobby = ["basketball"."football"];
}
/ / subclass
function Child() {}
/ / inheritance
Child.prototype = new Parent(); 
Copy the code

Question:

  1. If a parent property has a base data type, the instance cannot change the value of that property; The instance will add a property of the same name to the instance, and we can only operate on the new property



2. If the parent attribute is a reference type, modifying the value of the attribute affects all instances.Note that you do not assign the property directly. If you do, create a new property of the same name on the instance itself, just as with primitive data types)

3. When creating instances of subtypes, arguments cannot be passed to the parent class. 4. The constructor property of the original prototype object is lost because the prototype object has been replaced.

The child.constructor property follows the prototype chain directly to the __proto__ constructor property of new Parent()

Constructor inheritance

How it works: Use call or apply to execute the superclass constructor

// Constructor inheritance
/ / parent class
function Parent(name) {
    this.name = name;
}

/ / subclass
function Child() {
    Parent.apply(this.arguments);
}

let child = new Child("Vien");
console.log(child); // { name: 'Vien' }
Copy the code

advantages

  1. You can pass arguments to a parent class

disadvantages

  1. The superclass prototype object cannot be inherited; That is, the prototype object of the parent class is also invisible to the child class
  2. The constructor property of the original prototype object is lost because the prototype object has been replaced.

Combination of inheritance

Principle: Prototype chain inheritance + constructor inheritance

// constructor prototype chain combinatorial inheritance
/ / parent class
function Parent(name) {
    this.name = name;
}

Parent.prototype.sayName = function() {
    console.log(this.name);
};

/ / subclass
function Child() {
    // Call Parent for the first time
    Parent.apply(this.arguments); // The apply() method calls a function with a given this value and arguments in the form of an array (or array-like object).
}

// Prototype chain inheritance
Child.prototype = new Parent(); // Call Parent a second time

let child = new Child("Vien");
console.log(child); // { name: 'Vien' }
c.sayName(); // Panda
Copy the code

advantages

  1. Composite inheritance avoids the defects of stereotype chains and borrowed constructors, and combines their advantages to become the most common inheritance pattern in JavaScript.

disadvantages

  1. The parent class is executed twice, once when a property is inherited using Call or Apply, and again when an instance is created to replace the subclass stereotype.
  2. The constructor property of the original prototype object is lost because the prototype object has been replaced.

Primary inheritance

// Original type inheritance
/ / parent class
function Parent(name) {
    this.name = name;
}

/ / subclass
function Child() {
    Parent.apply(this.arguments);
}

// Inherit functions
function create(obj) {
    function F() {}
    F.prototype = obj;
    return new F();
}

/ / inheritance
Child.prototype = create(Parent.prototype); // Avoid instantiating Parent

let child = new Child("Vien");
console.log(child); // { name: 'Vien' }
Copy the code

Description:

  1. The original type of inheritance is actually with the aid of an intermediary constructor, replace the prototype of intermediate constructor F became the prototype of the parent classes, and created a F instance of returns, this example is that do not have any attributes (clean), replace subclass with the instance of the prototype, because the instance of the prototype of the prototype to F, The prototype of F is also the prototype object of the parent class, so the subclass instance inherits the method of the parent class prototype. The parent class only executes the method once when creating the subclass instance, eliminating the process of creating the parent class instance.
  2. Prototypal inheritance is encapsulated as a specialized approach in the ES5 standardObject.createThe first argument to this method is the same as that to be used as a prototype object, and the second argument passes an object that adds properties from the object to the prototype. The second argument makes up for the loss of constructor. This method is not compatible with earlier versions of IE.

disadvantages

  1. The constructor property of the original prototype object is lost because the prototype object has been replaced.

Parasitic inheritance

The problem: The biggest problem with composite inheritance is that in any case, the supertype constructor is called twice: once when the subtype stereotype is created and once inside the subtype constructor.

// Parasitic inheritance
/ / parent class
function Parent(name) {
    this.name = name;
}

/ / subclass
function Child() {
    Parent.apply(this.arguments);
}

// Inherit functions
function create(obj) {
    function F() {}
    F.prototype = obj;
    return new F();
}

// Privatize the subclass method function
function creatFunction(obj) {
    // Call the inheritance function
    let clone = create(obj); // 
    // Subclass prototype method (multiple)
    clone.sayName = function() {};
    clone.sayHello = function() {};

    return clone;
}

/ / inheritance
Child.prototype = creatFunction(Parent.prototype);
Copy the code

disadvantages

  1. Disadvantages: Because parasitic inheritance eventually returns an object, if you use a variable to receive it directly, all the added methods become the object itself. If you create more than one such object, you cannot reuse the same method.

Parasitic combinatorial inheritance

// Parasitic combinatorial inheritance
/ / parent class
function Parent(name, age) {
    this.name = name;
    this.age = age;
}

Parent.prototype.headCount = 1;
Parent.prototype.eat = function() {
    console.log("eating...");
};

/ / subclass
function Child(name, age) {
    Parent.apply(this.arguments);
}

// Parasitic combinatorial inheritance (subclass object inherits parent object)
function myCreate(Child, Parent) {
    function F() {}
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    // The constructor property repoints to the subclass constructor
    Child.prototype.constructor = Child;
    // Let the static properties super and Base of Child subclass point to the prototype of the parent class
    Child.super = Child.base = Parent.prototype;
}

// Call the method to implement inheritance
myCreate(Child, Parent);

// Add a property method to the subclass stereotype object, because the subclass constructor's stereotype was replaced, the property method is still after the replacement
Child.prototype.language = "javascript";
Child.prototype.work = function() {
    console.log("writing code use " + this.language);
};
Child.work = function() {
    this.super.eat();
};
Copy the code

Parasitic combinatorial inheritance basically circumvents most of the disadvantages of other inheritance and should be relatively powerful and the most commonly used type of inheritance. The purpose of the child.super method is to call the parent class’s prototype method when calling the static property of the Child class.

disadvantages

  1. A subclass does not inherit static methods from its parent class.

The class inheritance

Principle: Parasitic combination inheritance

// class... extends... inheritance
/ / parent class
class Parent {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        console.log(this.name);
    }
    static sayHi() {
        console.log("Hello"); }}// Subclasses inherit from their parent class
class Child extends Parent {
    constructor(name, age) {
        super(name, age); // Inherits the attributes of the parent class
    }
    sayHello() {
        Parent.sayHi();
    }
    static sayHello() {
        super.sayHi(); }}let child = new Child("Vien".18);

child.sayName(); // Vien
child.sayHello(); // Hello
Child.sayHi(); // Hello
Child.sayHello(); // Hello
Copy the code
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: []}instanceof Array && function (d, b) { d.__proto__ = b; }) | |function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    }
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new(4)); }; }) ();var Parent = / * *@class * / (function () {
    function Parent(name, age) {
        this.name = name;
        this.age = age;
    }
    Parent.prototype.sayName = function () {
        console.log(this.name);
    };
    Parent.sayHi = function () {
        console.log("Hello");
    };
    returnParent; } ());var Child = / * *@class * / (function (_super) {
    __extends(Child, _super);
    function Child(name, age) {
        return _super.call(this, name, age) || this;
    }
    Child.prototype.sayHello = function () {
        Parent.sayHi();
    };
    Child.sayHello = function () {
        _super.sayHi.call(this);
    };
    return Child;
}(Parent));
Copy the code

By calling supper from the constructor of the subclass, the attribute of the parent class can be inherited. The prototype method and static method of the parent class will be directly inherited by the subclass. If the prototype method of the subclass uses the prototype method of the parent class, you only need to call this or super, and this refers to the instance of the subclass. If you use this or super in a static method of a subclass to call a static method of the parent class, this refers to the subclass itself.

Refer to the article

How do I implement JavaScript’s new operator myself? JavaScript inheritance and its advantages and disadvantages