Conclusion:

  1. Class Can be achieved byextendsKeyword implementation inheritance, inheritance of the parent classAll properties and methodsWhether it’s public private or static
  2. Subclasses must be inconstructorMethod callsuperMethod, or an error will be reported when creating a new instance
  3. The inheritance of ES5 is essentiallyCreate a subclass firstInstance object ofthisAnd thenThe parent classMethod added tothisThe above (Parent.apply(this))
  4. ES6 has a completely different inheritance mechanism, essentiallyFirst the parent classProperties and methods of the instance object, added tothisAbove (so must be called firstsuperMethod), and then modify it with the constructor of the subclassthis
  5. In the constructor of a subclass, there are only callssuperAfter that, it can be usedthisThe keyword
  6. Object. GetPrototypeOf (), which is used toGets the parent class from a subclass
  7. The super keyword is okAs a functionUse, also canAs an objectuse
  8. Super as a function call,Represents the constructor of the parent classThis inside super refers to instances of subclasses
  9. When super is an object:

In a normal method, a prototype object that points to a parent class (public attributes can be obtained) :

Super.p () is the same as a.prototype.p ()

When a method of a subclass is called by super in a normal method of a subclass, this inside the method points to the current instance of the subclass

Assigning a property by super is the property of the subclass instance of the assigned property;

(1) When a static method of a subclass is called by super, this inside the method refers to the current subclass, not the instance of the subclass

  1. ES5 In the implementation, every object has it__proto__Property pointing to the corresponding constructorprototypeattribute
  2. ES6: (

1) The __proto__ attribute of a subclass, indicating the inheritance of the constructor, always points to the parent class

(2) The prototype attribute’s __proto__ attribute, indicating method inheritance, always points to the prototype attribute of the parent class

(3) __proto__ points to the prototype of the instance constructor

Prototype: __proto__ attribute (protoclass.prototype.__proto__), pointing to the __proto__ attribute (protoclass.prototype) of the protoclass instance. They all refer to the prototype of the parent class that is, the prototype of the subclass’s prototype is the prototype of the parent class

  1. Es5 Native constructorwillIgnore the applymethodsThe incoming thisThat is to say,Native constructortheThis cannot be bound, resulting inFailed to get internal attributes
  2. ES6Changed theObjectConstructor behavior, once discoveredObjectmethodsnotthroughnew Object()This form of call,ES6 provisionsObjectThe constructor willIgnore the parameters

Introduction to the

1.Class Can be achieved byextendsKeyword implementation inheritance, inheritance of the parent classAll properties and methods

2. Parent class and subclassNo code is deployed, these two classesExactly the same asIs equal toA parent class is copied

class Point {}class ColorPoint extends Point {}Copy the code

3, subclasses must be inconstructorMethod callsuperMethod, or an error will be reported when creating a new instance

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  toString(){}}class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // Call parent constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); // Call the parent toString()}}Copy the code

(1) Because: subclass ownthisObject, which must first be molded through the constructor of its parent class,Get the same instance properties and methods as the parent class, and then process it, adding the subclass’s own instance properties and methods

(2) IfDon't call superMethod, subclassYou can't get this object

(3) The inheritance of ES5 is in essenceCreate a subclass firstInstance object ofthisAnd thenThe parent classMethod added tothisThe above (Parent.apply(this))

(4) The inheritance mechanism of ES6 is completely different, in essenceFirst the parent classProperties and methods of the instance object, added tothisAbove (so must be called firstsuperMethod), and then modify it with the constructor of the subclassthis

(5) If the subclass is not definedconstructorMethod,superMethods are added by default

class ColorPoint extends Point {}/ / is equivalent to
class ColorPoint extends Point {
  constructor(. args) {
    super(...args);
  }
}
Copy the code

(6) In the constructor of a subclass, only the callsuperAfter that, it can be usedthisThe keyword

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y; }}class ColorPoint extends Point {
  constructor(x, y, color) {
    this.color = color; / / ReferenceError error
    super(x, y);
    this.color = color; / / right}}Copy the code
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y; }}class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y);
    this.color = color; / / right}}let cp = new ColorPoint(25.8.'green');

// cp is an instance of both ColorPoint and Point classes
cp instanceof ColorPoint // true
cp instanceof Point // true
Copy the code

Static methods of the parent class are also inherited by subclasses

class A {
  static hello() {
    console.log('hello world'); }}class B extends A {
}

B.hello()  // hello world
Copy the code

Object. GetPrototypeOf (), which is used toGets the parent class from a subclass

class Point {}class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); }}Object.getPrototypeOf(ColorPoint) === Point
// true
Copy the code

The super keyword is okAs a functionUse, also canAs an objectuse

1. Super as a function call,Represents the constructor of the parent class

(1)ES6 Constructor of the subclass requiredThe super function must be executed once

The subclass’s this object must first be molded by the parent class’s constructor to get the same instance attributes and methods as the parent class, and then be processed to add the subclass’s instance attributes and methods. If you don’t call super, your subclasses don’t get this.

class A {}

class B extends A {
  constructor() {
    super();
  }
}
Copy the code

(2) This inside super refers to instances of subclasses

superAlthough it represents the parent classAConstructor of, butThe returnedThe subclassBAn instance of the
namelyThis inside super refers to instances of B, sosuper()Here,Call (this) is equivalent to Amy polumbo rototype. Constructor.
class A {
  constructor() {
    console.log(new.target.name); }}class B extends A {
  constructor() {
    super();
  }
}
new A() // A
new B() // B
Copy the code

In the above code, new.target points to the function currently executing. As you can see, when super() executes, it points to the constructor of subclass B, not the constructor of superclass A. That is, the this inside super() refers to B.

(3) Super () can only be used in the constructor of a subclass

class A {}

class B extends A {
  m() {
    super(a);/ / an error}}Copy the code

2. When super is an object

2.1. In the normal method, point toThe prototype object of the parent class(Public attributes can be obtained)

(1) super.p() = a.prototype.p ()
class A {
  p() {
    return 2; }}class B extends A {
  constructor() {
    super(a);console.log(super.p()); / / 2}}let b = new B();
Copy the code

In the code above, super.p() in subclass B uses super as an object. In this case, super refers to a.prototype in normal methods, so super.p() equals a.prototype.p ().

(2) defined inOn the parent class instanceMethod or property ofCannot be called by super(Cannot get private property)

Since super refers to the prototype object of the parent class, methods or properties defined on instances of the parent class cannot be called by super.

class A {
  constructor() {
    this.p = 2; }}class B extends A {
  get m() {
    return super.p; }}let b = new B();
b.m // undefined
Copy the code

In the code above, p is an attribute of an instance of superclass A. super.p does not refer to it.

(3) Super can fetch attributes defined on the superclass prototype (superclass. Prototype) object
class A {}
A.prototype.x = 2;

class B extends A {
  constructor() {
    super(a);console.log(super.x) / / 2}}let b = new B();
Copy the code
(4) When a method of a subclass is called by super, the this inside the method refers to the currentThe subclass instance
class A {
  constructor() {
    this.x = 1;
  }
  print() {
    console.log(this.x); }}class B extends A {
  constructor() {
    super(a);this.x = 2;
  }
  m() {
    super.print(); }}let b = new B();
b.m() / / 2
Copy the code

In the code above, super.print() calls a.prototype.print (), but the this inside a.prototype.print () points to an instance of subclass B, resulting in 2 instead of 1. That is, super.print.call(this) is actually executed.

(5) Assign a value to an attribute via super, which is assignedThe subclass instanceThe properties of the

We said that this refers to the subclass instance, so if you assign a value to a property by super, then super is this, and the assigned property becomes the property of the subclass instance.

class A {
  constructor() {
    this.x = 1; }}class B extends A {
  constructor() {
    super(a);this.x = 2;
    super.x = 3;// assign super.x to 3, which is equivalent to assigning this.x to 3
    console.log(super.x); // undefined
    console.log(this.x); / / 3}}let b = new B();
Copy the code

In the code above, assigning super.x to 3 is the same as assigning this.x to 3. When super.x is read, a.prototype. x is read, so return undefined.

2.2. In static methods, point toThe parent class

In static methods, super will point to the parent class, not the parent class’s prototype object.

class Parent {
  static myMethod(msg) {
    console.log('static', msg);
  }

  myMethod(msg) {
    console.log('instance', msg); }}class Child extends Parent {
  static myMethod(msg) {
    super.myMethod(msg);
  }

  myMethod(msg) {
    super.myMethod(msg);
  }
}

Child.myMethod(1); // static 1 calls the static method of the subclass, pointing to the static method of the parent class

var child = new Child();
child.myMethod(2); // instance 2 calls the normal methods of the subclass through the instance of the subclass, pointing to the parent class
Copy the code
(1)A static method of a subclassThrough thesuperWhen a method of a parent class is calledthisPoint to theCurrent subclassAnd theIs not an instance of a subclass
class A {
  constructor() {
    this.x = 1;
  }
  static print() {
    console.log(this.x); }}class B extends A {
  constructor() {
    super(a);this.x = 2;
  }
  static m() {
    super.print(); }}// Set attribute x for subclasses
B.x = 3;
B.m() / / 3
Copy the code

In the code above, in the static method B.m, super.print points to the static method of the parent class. This in this method refers to B, not an instance of B.

3. When using super, you must explicitly specify whether it is used as a function or as an object. Otherwise, an error will be reported

class A {}

class B extends A {
  constructor() {
    super(a);console.log(super); / / an error}}Copy the code

4. You can use the super keyword in any object

Since objects always inherit from other objects, the super keyword can be used in any object.

var obj = {
  toString() {
    return "MyObject: " + super.toString(); }}; obj.toString();// MyObject: [object Object]
Copy the code

Class prototype properties and__proto__attribute

ES5 In the implementation, every object has it__proto__Property pointing to the corresponding constructorprototypeattribute

ES6:

(1) subclass__proto__Attribute, representingConstructor inheritance, alwaysPoints to the parent class

(2) SubclassesprototypeProperties of the__proto__Attribute, representingMethod inheritance, alwaysThe Prototype property pointing to the parent class

The two lines of inheritance can be understood as follows:

(1) As aobjectSubclasses (B) prototype (__proto__Property) is the parent class (A)

(2) as aThe constructorSubclasses (B) prototype object (prototypeProperty) is an instance of the parent class’s prototype object (prototype property)

class A {}class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
Copy the code

Class inheritance implementation pattern

Object.setprototypeof (b.prototype, a.prototype)

(2) object.setProtoTypeof (B, A)

class A {}class B {}// Instance B inherits instance A
Object.setPrototypeOf(B.prototype, A.prototype);

// B inherits A's static attributes
Object.setPrototypeOf(B, A);

const b = new B();
Copy the code

Object. SetPrototypeOf method implementation,obj.__proto__ = proto

Object.setPrototypeOf = function (obj, proto) {
  obj.__proto__ = proto;
  return obj;
}
Copy the code
Object.setPrototypeOf(B.prototype, A.prototype);
/ / is equivalent to
B.prototype.__proto__ = A.prototype;

Object.setPrototypeOf(B, A);
/ / is equivalent to
B.__proto__ = A;
Copy the code
B.prototype = Object.create(A.prototype);
/ / is equivalent to
B.prototype.__proto__ = A.prototype;
Copy the code

The extends keyword can be followed by many types of values

class B extends A {}Copy the code

A of the above code, as long as it is A function with the prototype property, can be inherited by B. Since all functions have the prototype attribute (except the function. prototype Function), A can be any Function.

(1) Subclasses inherit from the Object class

class A extends Object {
}

A.__proto__ === Object // true
A.prototype.__proto__ === Object.prototype // true
Copy the code

A is A copy of the constructor Object, and an instance of A is an instance of Object

(2), there is no inheritance

class A {
}

A.__proto__ === Function.prototype // true
A.prototype.__proto__ === Object.prototype // true
Copy the code
AAs a base class (that is, without any inheritance), it is a normal function, so it inherits directlyFunction.prototype
However,AReturns an empty object (that isObjectInstance), soA.prototype.__proto__Pointing constructorObjecttheprototypeattribute

The instance__proto__ attribute

The instance__proto__Object pointing to the instance constructorprototype

Of a subclass instance__proto__Property (subclass.prototype)__proto__Property (subclass.prototype.__proto__) that points to an instance of the parent class__proto__Property (parent class. Prototype). All refer to the prototype of the parent class,The prototype of a subclass's prototype is the prototype of its parent class

class A{}class B  extends A{
    constructor(){
        super();
    }
}
var p1=new A();
var p2=new B();
// The __proto__ attribute of the subclass instance always points to the prototype attribute of the subclass
console.log(p2.__proto__ === B.prototype); // true

// The prototype attribute's __proto__ attribute, representing method inheritance, always points to the prototype attribute of the parent class
console.log(B.prototype.__proto__ === A.prototype); // true

/ / that
console.log(p2.__proto__.__proto__ === A.prototype); // true
// The __proto__ attribute of the parent class instance always points to the prototype attribute of the parent class
console.log(p1.__proto__ === A.prototype); // true

// Final result
console.log(p2.__proto__.__proto__ === p1.__proto__); // true
Copy the code

In the above code, B inherits A, resulting in the prototype of the former prototype being the prototype of the latter (B.prototype.__proto__ === A.prototype).

You can modify the behavior of a subclass instance through the __proto__.__proto__ attribute of a subclass instance

p2.__proto__.__proto__.printName = function () {
  console.log('Ha');
};

p1.printName() // "Ha"
Copy the code

Inheritance of the native constructor

Native constructorRefers to theLanguage built-in constructorsUsually,Used to generate data structures

  • Boolean()
  • Number()
  • String()
  • Array()
  • Date()
  • Function()
  • RegExp()
  • Error()
  • Object()

Previously, native constructors could not be inherited

1, becauseES5 Is the instance object of the new subclassthis, and then add the attributes of the parent class to the subclass, because the internal attributes of the parent class cannot be obtained, so that the native constructor cannot be inherited

For example, define a subclass of Array:

function MyArray() {
  Array.apply(this.arguments);
}

MyArray.prototype = Object.create(Array.prototype, {
  constructor: {
    value: MyArray,
    writable: true.configurable: true.enumerable: true}});var colors = new MyArray();
colors[0] = "red";
colors.length  / / 0

colors.length = 0;
colors[0]  // "red"
Copy the code

The MyArray class, which inherits from Array, behaves completely differently from Array. The reason: subclasses cannot get the internal properties of the native constructor

2,Native constructorwillIgnore the applymethodsThe incoming thisThat is to say,Native constructortheThis cannot be bound, resulting inFailed to get internal attributes

ES6 allows subclasses to inherit from native constructors

1.ES6Is the instance object of the new parent classthisWe then decorate this with the constructor of the subclass so that all the behavior of the parent class can be inherited

This means that ES6 can customize subclasses of native data structures such as Array, String, and so on, which ES5 cannot.

Examples of inheriting an Array:

class MyArray extends Array {
  constructor(. args) {
    super(...args);
  }
}

var arr = new MyArray();
arr[0] = 12;
arr.length / / 1

arr.length = 0;
arr[0] // undefined
Copy the code

2,extendsKeywords can be used to extend not only classes, but also native constructors

Therefore, you can define your own data structure based on the native data structure.

An array with version functionality:
class VersionedArray extends Array {
  constructor() {
    super(a);this.history = [[]];
  }
  commit() {
    this.history.push(this.slice());
  }
  revert() {
    this.splice(0.this.length, ... this.history[this.history.length - 1]); }}var x = new VersionedArray();

x.push(1);
x.push(2);
x / / [1, 2]
x.history / / [[]]

x.commit();
x.history / / [[], [1, 2]]

x.push(3);
x / / [1, 2, 3]
x.history / / [[], [1, 2]]

x.revert();
x / / [1, 2]
Copy the code

In the code above, VersionedArray uses the COMMIT method to generate a version snapshot of its current state and store it in the history property. The Revert method is used to reset an array to the most recently saved version. In addition, VersionedArray is still a normal array on which all native array methods can be called.

Custom Error subclasses to customize the behavior when reporting an Error
class ExtendableError extends Error {
  constructor(message) {
    super(a);this.message = message;
    this.stack = (new Error()).stack;
    this.name = this.constructor.name; }}class MyError extends ExtendableError {
  constructor(m) {
    super(m); }}var myerror = new MyError('ll');
myerror.message // "ll"
myerror instanceof Error // true
myerror.name // "MyError"
myerror.stack
// Error
// at MyError.ExtendableError
/ /...
Copy the code
Subclasses that inherit Object have a behavior difference
class NewObj extends Object{
  constructor(){
    super(...arguments);
  }
}
var o = new NewObj({attr: true});
o.attr === true  // false
Copy the code

In the code above, NewObj inherits Object, but cannot pass an argument to its parent Object using the super method.

This is becauseES6Changed theObjectConstructor behavior, once discoveredObjectmethodsnotthroughnew Object()This form of call,ES6 provisionsObjectThe constructor willIgnore the parameters

Implementation of Mixin patterns

A Mixin is a new object composed of multiple objects with interfaces for its constituent members

The simplest implementation is as follows

const a = {
  a: 'a'
};
const b = {
  b: 'b'
};
constc = {... a, ... b};// {a: 'a', b: 'b'}
Copy the code

More complete implementation

Mix in interfaces from multiple classes into another class

function mix(. mixins) {
  class Mix {
    constructor() {
      for (let mixin of mixins) {
        copyProperties(this.new mixin()); // Copy the instance properties}}}for (let mixin of mixins) {
    copyProperties(Mix, mixin); // Copy static properties
    copyProperties(Mix.prototype, mixin.prototype); // Copy the stereotype properties
  }

  return Mix;
}

function copyProperties(target, source) {
  for (let key of Reflect.ownKeys(source)) {
    if( key ! = ='constructor'&& key ! = ='prototype'&& key ! = ='name'
    ) {
      let desc = Object.getOwnPropertyDescriptor(source, key);
      Object.defineProperty(target, key, desc); }}}Copy the code

When used, simply inherit the class

class DistributedEdit extends mix(Loggable.Serializable) {
  // ...
}
Copy the code