Parasitic combinatorial inheritance of ES5

function animals (animal) { this.animal = animal } animals.prototype.say = function () { console.log(this.animal) } function sub (animal, value) { animals.call(this, animal) this.value = value } sub.prototype = Object.create(animals.prototype, { constructor: { value: sub, enumerable: // The writable 64x works without any additional information, and is freely configurable}})Copy the code

The Class ES6

ES6 classes can be seen as just a syntactic candy. ES5 can do most of the things it does. The new class writing method just makes object prototype writing clearer and more like object-oriented programming syntax. But there are differences.

The difference between:

  • The class must be called with new or an error will be reported. ES5 constructors can be used as normal functions
  • All methods defined inside a class are not enumerable. (Including internally defined static methods)
  • Static methods of a class can also be inherited by subclasses
  • Native constructors can be inherited
    • ES5 creates the instance object this of the subclass first, and then adds the attributes of the parent class to the subclass. Because the internal attributes of the parent class cannot be obtained, it cannot inherit the native constructor.
    • ES6 allows subclasses to be inherited from native constructors, because ES6 creates an instance object of the parent class, this, and then decorates this with the constructor of the subclass, making all behavior of the parent class inheritable

Use ES5 simulation to implement ES6 class

Based on the above differences, let’s look at step by step.

1. The new operator checks the function

Solve a problem:

  • The class must be called with new or an error will be reported. The ES constructor can be used as a normal function
function _checkType (obj, constructor) { if (! (obj instanceof constructor)) { throw new TypeError('Cannot call a class as a function') } }Copy the code

2. Internal methods cannot be enumerated

Solve a problem:

  • All methods defined inside a class are not enumerable. (Including internally defined static methods)
// Modify the constructor descriptor function defineProperties (target, descriptors) { for (let descriptor of descriptors) { descriptor.enumerable = descriptor.enumerable || false descriptor.configurable = true if ('value' in descriptor) { descriptor.writable = true } Object.defineProperty(target, descriptor.key, Descriptor)}} // constructor indicates the constructor object corresponding to the class. // protoDesc indicates the method defined inside the class. // staticDesc indicates the static method defined inside the class  function _createClass (constructor, protoDesc, staticDesc) { protoDesc && defineProperties(constructor.prototype, protoDesc) staticDesc && defineProperties(constructor, staticDesc) return constructor }Copy the code

3. Actually create the class

const Foo = function () { function Foo(name) { _checkType(this, This.name = name} _createClass (Foo, [// indicates the method defined inside the class {key: 'say', value: Function () {console.log(this.name)}}], [// static method defined inside the class {key: 'say', value: function () { console.log('static say') console.log(this.name) } } ]) return Foo }()Copy the code

So let’s verify that class implementation is done here.

  • So let’s call it directlyFoo(), the result is:

  • Use the new operator to generate an object
const foo = new Foo('aaa')
Copy the code

  • Print the methods defined on the prototype chain

You can see that the SAY method is not enumerable.

  • Print the static method

See that the static method say is not enumerable.

4. Implement prototype chain inheritance and static method inheritance, and allow for the possibility of null inheritance

Solve a problem:

  • Static methods of a class can also be inherited by subclasses
function _inherits(subClass, superClass) { if (typeof superClass ! == 'function' && superClass ! == null) { throw new TypeError('Super expression must either be null or a function, not' + typeof superClass) } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: True}}) if (superClass) {// Set superClass to object.setPrototypeof? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass } }Copy the code

5. Use this instance object of the parent class

Problems solved:

  • Native constructors can be inherited
    • ES5 creates the instance object this of the subclass first, and then adds the attributes of the parent class to the subclass. Because the internal attributes of the parent class cannot be obtained, it cannot inherit the native constructor.
    • ES6 allows subclasses to be inherited from native constructors, because ES6 creates an instance object of the parent class, this, and then decorates this with the constructor of the subclass, making all behavior of the parent class inheritable
// Return this; If null, the return to its own function _possibleConstructorReturn {(self, call) if (! self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called") } return call && (typeof call === 'object' || typeof call === 'function') ? call : self }Copy the code

6. Create a subclass

Const Child = function (_Parent) {_inherits(Child, _Parent) const Child = function (_Parent) {_inherits(Child, _Parent); Age) {_checkType(this, Child); Return const _this = _possibleConstructorReturn (this, (Child. __proto__ | | Object. GetPrototypeOf (Child)). The call (this, name)) _this.age = age return _this } return Child }(Foo)Copy the code

The subclass implementation is complete. Let’s verify that.

  • Print child.say ()

The Child does not define static methods on its own, but its parent does. Inheritance succeeded.

  • Construct a subclass that inherits the native constructor
const Child = function (_Parent) {
    _inherits(Child, _Parent)
    function Child(name, age) {
      _checkType(this, Child)
      const _this = _possibleConstructorReturn(this, (
          Child.__proto__ 
          || Object.getPrototypeOf(Child)).call(this, name)
        )
        _this.age = age
        return _this
    }
    return Child
}(Array)
const c = new Child('bbb', 12)
Copy the code

Inheritance succeeded. The basic realization of ES5 function to achieve the effect of ES6 class.