gnosis23 / hello-world-blog

还是 issues 里面写文章方便
https://bohao.work
0 stars 0 forks source link

Babel.js 如何转化 class #1

Open gnosis23 opened 6 years ago

gnosis23 commented 6 years ago

Babel.js 如何转化 class

Basic Class

源代码来自 Chrome Samples

class Polygon {
  constructor(height, width) {
    this.name = 'Polygon';
    this.height = height;
    this.width = width;
  }

  sayName() {
    ChromeSamples.log('Hi, I am a ', this.name + '.');
  }

  sayHistory() {
    ChromeSamples.log('"Polygon" is derived from the Greek polus (many) ' +
      'and gonia (angle).');
  }

  static triple(n) {
    n = n || 1;
    return n * 3;
  } 
}

上面的代码会被转译成:

var Polygon = (function() {
  function Polygon(height, width) {
    _classCallCheck(this, Polygon);

    this.name = "Polygon";
    this.height = height;
    this.width = width;
  }

  _createClass(
    Polygon,
    [{
      key: "sayName",
      value: function sayName() {
        ChromeSamples.log("Hi, I am a ", this.name + ".");
      }
    }, {
      key: "sayHistory",
      value: function sayHistory() {
        ChromeSamples.log(
          '"Polygon" is derived from the Greek polus (many) ' +
            "and gonia (angle)."
        );
      }
    }],
    [{
      key: "triple",
      value: function triple(n) {
        n = n || 1;
        return n * 3;
      }
    }]
  );

  return Polygon;
})();
gnosis23 commented 5 years ago

_createClass

创建基础类

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

以下两件事:

注意拷贝的方式为 Object.defineProperty ,并且默认是不能枚举 ( enumerable ) 和可修改的 ( configurable ) 。

继承类

我们的代码如下

class Rectangle extends Polygon {
  constructor(height, width) {
    super(height, width);
    this.name = 'Rectangle';
  }

  sayName() {
    ChromeSamples.log('Sup! My name is ', this.name + '.');
    super.sayHistory();
  }
}

被转化成了下面代码

var Rectangle = (function(_Polygon) {
  _inherits(Rectangle, _Polygon);

  function Rectangle(height, width) {
    _classCallCheck(this, Rectangle);

    var _this = _possibleConstructorReturn(
      this,
      (Rectangle.__proto__ || Object.getPrototypeOf(Rectangle)).call(
        this,
        height,
        width
      )
    );

    _this.name = "Rectangle";
    return _this;
  }

  _createClass(Rectangle, [
    {
      key: "sayName",
      value: function sayName() {
        ChromeSamples.log("Sup! My name is ", this.name + ".");
        _get(
          Rectangle.prototype.__proto__ ||
            Object.getPrototypeOf(Rectangle.prototype),
          "sayHistory",
          this
        ).call(this);
      }
    }
  ]);

  return Rectangle;
})(Polygon);

我们发现 super 好像被翻译成了 (Rectangle.proto || Object.getPrototypeOf(Rectangle))

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

gnosis23 commented 5 years ago

_possibleConstructorReturn

//  var _this = _possibleConstructorReturn(
//       this,
//       (Rectangle.__proto__ || Object.getPrototypeOf(Rectangle)).call(
//         this,
//         height,
//         width
//       )
//   );
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;
}

构造函数有返回值的时候返回,否则返回 this。

_get

// super.sayHistory();
// _get(
//   Rectangle.prototype.__proto__ ||
//     Object.getPrototypeOf(Rectangle.prototype),
//   "sayHistory",
//   this
// ).call(this);
var _get = function get(object, property, receiver) {
  if (object === null) object = Function.prototype; // ??? 1
  var desc = Object.getOwnPropertyDescriptor(object, property);
  if (desc === undefined) {
    var parent = Object.getPrototypeOf(object);
    if (parent === null) {
      return undefined;
    } else {
      return get(parent, property, receiver);
    }
  } else if ("value" in desc) {
    return desc.value;
  } else {
    var getter = desc.get;
    if (getter === undefined) {
      return undefined;
    }
    return getter.call(receiver); // ??? 2
  }
};