babel 如何转义extends

接着上一篇文章,我们继续进行extends的解析。

开始之前,我们先要回顾一下ES5的继承,以前实现继承也不是一件容易的事情,常用的方法有构造函数继承,原型继承,组合继承,寄生式继承和寄生组合式继承等,构造函数继承中每个子类的属性和方法都是独立,太浪费内存,原型继承虽然实现了方法的共享,但是存在子类修改公共方法,影响其他子类的问题等,那么babel是如何来处理继承的呢,接下来我们通过babel官网提供的工具看一下:

// 原始代码
class Father {
    name = 'iwen'
    age = 18
    run() {}
    run2() {}
    static talk() { }
    static age2 = 19
}

class Child  extends Father{};


// babel 处理后代码
"use strict";

function _typeof(obj) {
  "@babel/helpers - typeof";
  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
    _typeof = function _typeof(obj) {
      return typeof obj;
    };
  } else {
    _typeof = function _typeof(obj) {
      return obj &&
        typeof Symbol === "function" &&
        obj.constructor === Symbol &&
        obj !== Symbol.prototype
        ? "symbol"
        : typeof obj;
    };
  }
  return _typeof(obj);
}

function _inherits(subClass, superClass) {
  if (typeof superClass !== "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);
}

function _createSuper(Derived) {
  var hasNativeReflectConstruct = _isNativeReflectConstruct();
  return function () {
    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 _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;
}

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 _getPrototypeOf(o) {
  _getPrototypeOf = Object.setPrototypeOf
    ? Object.getPrototypeOf
    : function _getPrototypeOf(o) {
        return o.__proto__ || Object.getPrototypeOf(o);
      };
  return _getPrototypeOf(o);
}

function _instanceof(left, right) {
  if (
    right != null &&
    typeof Symbol !== "undefined" &&
    right[Symbol.hasInstance]
  ) {
    return !!right[Symbol.hasInstance](left);
  } else {
    return left instanceof right;
  }
}

function _classCallCheck(instance, Constructor) {
  if (!_instanceof(instance, Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

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);
  }
}

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

function _defineProperty(obj, key, value) {
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true,
    });
  } else {
    obj[key] = value;
  }
  return obj;
}

var Father = /*#__PURE__*/ (function () {
  function Father() {
    _classCallCheck(this, Father);

    _defineProperty(this, "name", "iwen");

    _defineProperty(this, "age", 18);
  }

  _createClass(
    Father,
    [
      {
        key: "run",
        value: function run() {},
      },
      {
        key: "run2",
        value: function run2() {},
      },
    ],
    [
      {
        key: "talk",
        value: function talk() {},
      },
    ]
  );

  return Father;
})();

_defineProperty(Father, "age2", 19);

var Child = /*#__PURE__*/ (function (_Father) {
  _inherits(Child, _Father);

  var _super = _createSuper(Child);

  function Child() {
    _classCallCheck(this, Child);

    return _super.apply(this, arguments);
  }

  return Child;
})(Father);

在线查看

其中类相关的代码我们之前已经解释过了,这里只对继承相关的代码的解释。

_typeof(obj)
判断传入对象类型,如果Symbol存在使用typeof,如果不存在,判断是否为Symbol的实例,否则依然用typeof判断。

_inherits(subClass, superClass)    
实现继承的关键步骤,主要是原型链相关的设置,传入子类和父类,将子类原型对象指向父类原型对象,将父类的constructor指向子类,并通过_setPrototypeOf设置子类的原型链引用。

_setPrototypeOf(o, p)
如果Object.setPrototypeOf存在,则使用Object.setPrototypeOf设置原型链引用,不存则使用__proto__。

_createSuper(Derived)
实现继承的关键步骤,主要是生成了一个result对象,这个对象继承了父类上属性和方法,之后会通过apply方法将子类的this指向这个对象,具体解释已在代码中注释:

function _createSuper(Derived) {
  // 判断是否支持反射
  var hasNativeReflectConstruct = _isNativeReflectConstruct();
  return function () {
    // 获取父类
    var Super = _getPrototypeOf(Derived),
      result;
    if (hasNativeReflectConstruct) {
        // 这里的this通过后面的apply方法指向了创建的实例对象
        // _getPrototypeOf(this) 其实就是实例 (new Child()).__proto__ === Child.prototype
      	// NewTarget其实就是子类的构造函数,具体参考_inherits 方法第5行
        var NewTarget = _getPrototypeOf(this).constructor; 
      // Reflect.construct 可以拆分两步,1. const o = new Super(arguments);  2. o.prototype = NewTarget;
      result = Reflect.construct(Super, arguments, NewTarget);
    } else {
      result = Super.apply(this, arguments);
    }
    // 判断 result 的类型
    return _possibleConstructorReturn(this, result);
  };
}

**_possibleConstructorReturn(self, call)、_assertThisInitialized(self)
如果result是对象或者函数时返回result,否则判断this,如果this是undefined,报错,否则返回。这里有个小知识点,通过 self === void 0 判断this是否为undefined,主要是为了防止非严格模式下undefined被重写。

**_isNativeReflectConstruct()    **
判断浏览器是否支持反射。

其他都是之前讲过的内容,这里就不在重复了,以上就是实现继承用到的所有工具方法了,之后就是转化后的代码,明白了上面的工具方法,下面的代码就很好理解了。

var Child = /*#__PURE__*/ (function (_Father) {
  // 继承父类的原型对象和原型链
  _inherits(Child, _Father);
	
  // 创建一个父类的实例
  var _super = _createSuper(Child);

  function Child() {
    _classCallCheck(this, Child);
		
    // 将父类实例中的this指向子类
    return _super.apply(this, arguments);
  }

  return Child;
})(Father);

以上就是babel实现继承的所有代码,虽然日常工作中不再需要我们手动实现类和继承了,但是通过对babel转义class和extends的代码解析,让我们对babel运行原理有一个基本认识,同时也温习了以前实现类和继承的相关知识。如果要手动实现一个完美的类和继承上面就是最佳实践了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章