看啥推荐读物
专栏名称: Xiaowei
前端工程师
今天看啥  ›  专栏  ›  Xiaowei

日常好奇-看看ES6的类如何实现的[二]

Xiaowei  · 掘金  ·  · 2018-07-18 23:58
阅读 3

日常好奇-看看ES6的类如何实现的[二]

在上一篇中我们看了没有继承的实现,这一篇我们看下继承的实现

继承的实现

还是用这个继承的例子:

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

  getName() {
    return this.name;
  }
}

class Dog extends Animal{
  constructor(name) {
    super(name);
    this.name = name;
  }
}
复制代码

我们babel一下,得到如下代码:

"use strict";

var _createClass = 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);
    }
  }
  return function (Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps);
    if (staticProps) defineProperties(Constructor, staticProps);
    return Constructor;
  };
}();

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

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) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

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

var Animal = function () {
  function Animal(name) {
    _classCallCheck(this, Animal);

    this.name = name;
  }

  _createClass(Animal, [{
    key: "getName",
    value: function getName() {
      return this.name;
    }
  }]);

  return Animal;
}();

var Dog = function (_Animal) {

  _inherits(Dog, _Animal);

  function Dog(name) {
    _classCallCheck(this, Dog);

    var _this = _possibleConstructorReturn(this, (Dog.__proto__ || Object.getPrototypeOf(Dog)).call(this, name));

    _this.name = name;
    return _this;
  }

  return Dog;
}(Animal);
复制代码

Animal的代码与上节非继承的方式一致,直接跳过,来看下最后一部分Dog的代码:

// 这还是一个高阶函数,与没有继承的对象相比,这里多出了两个函数_inherits和_possibleConstructorReturn
var Dog = function (_Animal) {

  // 继承函数,继承Animal的属性
  _inherits(Dog, _Animal);

  function Dog(name) {
    _classCallCheck(this, Dog);

    // 获取this
    var _this = _possibleConstructorReturn(this, (Dog.__proto__ || Object.getPrototypeOf(Dog)).call(this, name));

    _this.name = name;
    return _this;
  }

  return Dog;
}(Animal);
复制代码

在来看_inherits如何实现的:

// 继承函数
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);
  }

  // 将父函数构造器的prototype“拷贝”(使用原型链的方式并不是真正的赋值)一份给子函数构造器的prototype
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });

  // 设定子函数构造器的原型为父函数构造器
  if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
复制代码

这里面涉及到了subClass.__proto__subClass.prototype,那么__proto__prototype的区别是什么?

实际上__proto__是真正查找时所用的对象,而prototype是当你用new关键在来构建对象时被用来建造__proto__的,Object.getPrototypeof(dog) === dog.__proto__ === Dog.prototype

函数__possibleConstructorReturn处理了构造函数有返回值的情况。这种情况下,需要改变this使用该返回值作为this

// 构造函数有返回值的情况
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;
}
复制代码

实际模拟

看了上面的实现,我们模拟这个步骤,为了简化我们省去错误处理和特殊情况。

var Animal = function(name) {
  this.name = name;
}

Animal.prototype.getName = function() {
  return this.name;
}

var Dog = function(name) {

  Animal.call(this.name);
  _this.name = name;
}

Dog.prototype = Animal.prototype;
复制代码

实现完成后发现,跟我们上一篇文章结尾,猜想实现的一样,这就很尴尬,本来觉得这种写法不太顺眼,看官方的支持,现在看起来就顺眼多了-_-。与完整实现相比我们缺少了一些原型赋值的步骤Dog.__proto__ = Animal,但总体来说原理是一样的。




原文地址:访问原文地址
快照地址: 访问文章快照