preface

In javascript, instance objects are generated by creating a function and instantiating the function object as new. This scheme is very different from traditional language and can easily confuse people. Es6 provides a more traditional language version: class. However, class can be thought of as syntactic sugar, and ES5 can do most of what it does. Let’s explore how class is implemented in ES5.

Written es6

class A {
  constructor(name) {
    this.name = name;
  }

  say() {
    console.log(this.name); }}class B extends A {
  constructor() {
    super();
  }
}
Copy the code

Here we define two classes, A and B, and B inherits from A.

Next, we get the following code under Babel escape

var A = /*#__PURE__*/ (function () {
  function A(name) {
    _classCallCheck(this, A);
    this.name = name;
  }
  _createClass(A, [
    {
      key: 'say'.value: function say() {
        console.log(this.name); }},]);returnA; }) ();var B = /*#__PURE__*/ (function (_A) {
  _inherits(B, _A);
  var _super = _createSuper(B);
  function B() {
    _classCallCheck(this, B);
    return _super.call(this);
  }
  return B;
})(A);
Copy the code

As you can see, class is actually implemented by function

Class implementation principles

Let’s look at the implementation of class through A

First, variable A is assigned A self-executing function that returns internally defined function A, so variable A is A function.

Then, in addition to the instance assignment, _classCallCheck(this,A) is called internally.

function _classCallCheck(instance, Constructor) {
  if(! _instanceof(instance, Constructor)) {// same as! (this instanceof A)
    throw new TypeError('Cannot call a class as a function'); }}Copy the code

That is, if you do not call the function with the new keyword, this instanceof A will be false, return true, and raise the exception. This is why class cannot be executed directly as a function.

_createClass

Next, after the function is created, the _createClass function is called. This function passes two values. The first is function A, and the second is an array containing the function say defined in class A.

function _createClass(Constructor, protoProps, staticProps) {
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  if (staticProps) _defineProperties(Constructor, staticProps);
  return Constructor;
}

function _defineProperties(target, props) {
  for (var i = 0; i < props.length; i++) {
    var descriptor = props[i];
    descriptor.enumerable = descriptor.enumerable || false;
    descriptor.configurable = true;
    if ('value' in descriptor) descriptor.writable = true;
    Object.defineProperty(target, descriptor.key, descriptor); }}Copy the code
 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
Copy the code

through_createClassWe’re going to do that_definePropertiesConstructor is the function A, so the first argument is equal to a.prototype and the second argument is the array holding the say function

This is done by iterating through an array of functions and storing the corresponding function to target (a.protoType) with Object.defineProperty

Finally, function A is assigned function A, and function A’s prototype has say

Principle of inheritance

var B = /*#__PURE__*/ (function (_A) {
  _inherits(B, _A);
  var _super = _createSuper(B);
  function B() {
    _classCallCheck(this, B);
    return _super.call(this);
  }
  return B;
})(A);
Copy the code

As you can see, B is A self-executing function, just like A, but B takes one argument, which is function A

The self-executing function of B first executes _inherits(B, _A)

function _inherits(subClass, superClass) {
  if (typeofsuperClass ! = ='function'&& superClass ! = =null) {
    throw new TypeError('Super expression must either be null or a function');
  }
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: { value: subClass, writable: true.configurable: true}});if (superClass) _setPrototypeOf(subClass, superClass);
}

function _setPrototypeOf(o, p) {
  _setPrototypeOf =
    Object.setPrototypeOf ||
    function _setPrototypeOf(o, p) {
      o.__proto__ = p;
      return o;
    };
  return _setPrototypeOf(o, p);
}
Copy the code

Here, first let b.prototype._proto_ = a.prototype and constructor point to B. Next, execute _setPrototypeOf, making B._proto = A.

So, _inherits is to construct A prototype chain between B and A

super

Next, create super

var _super = _createSuper(B);

function _createSuper(Derived) {
  var hasNativeReflectConstruct = _isNativeReflectConstruct();
  return function _createSuperInternal() {
    var Super = _getPrototypeOf(Derived),
      result;
    if (hasNativeReflectConstruct) {
      var NewTarget = _getPrototypeOf(this).constructor;
      result = Reflect.construct(Super, arguments, NewTarget);
    } else {
      result = Super.apply(this.arguments);
    }
    return _possibleConstructorReturn(this, result);
  };
}

function _isNativeReflectConstruct() {
  if (typeof Reflect= = ='undefined' || !Reflect.construct) return false;
  if (Reflect.construct.sham) return false;
  if (typeof Proxy= = ='function') return true;
  try {
    Date.prototype.toString.call(Reflect.construct(Date[],function () {}));
    return true;
  } catch (e) {
    return false; }}function _possibleConstructorReturn(self, call) {
  if (call && (_typeof(call) === 'object' || typeof call === 'function')) {
    return call;
  }
  return _assertThisInitialized(self);
}

function _assertThisInitialized(self) {
  if (self === void 0) {
    throw new ReferenceError(
      "this hasn't been initialised - super() hasn't been called"
    );
  }
  return self;
}
Copy the code

Reflect is the new ES6 operation object API, in order to determine whether Reflect can be used, use Reflect. Let’s ignore Reflect and go straight to Reflect’s unusable logic

 var Super = _getPrototypeOf(Derived) // Get the prototype of Derived B
 result = Super.apply(this.arguments); // Call A, passing this instance and arguments
Copy the code

As you can see, _createSuper returns A function that executes the prototype of the current function, which executes A. That is, inheritance by borrowing constructors. This is why subclasses must call the super method from the constructor method, because their own this object must first be molded by the parent class’s constructor to get the same instance properties and methods as the parent class.

Will end by _possibleConstructorReturn judge whether the execution of the parent function returns an object, if is an object, finally returned to the parent () function returns the object.

conclusion

These are basically the principles of ES6 inheritance.

The first time to write an article, write not good, please forgive, if there is a problem in the article, welcome to comment, I will correct in time.