ES5实现继承
熟悉了解 ES5 继承方式的同学可能都已经比较熟悉以下寄生组合式继承的方式(未考虑兼容性):
(function() {
// 原型式继承。也可以通过 Object.create() 来实现
function object(prototype) {
function F() {}
F.prototype = prototype;
return new F();
}
// 继承原型并修改 constructor 指向
function inheritProtoType(source, target) {
const temp = object(target.prototype)
temp.constructor = source;
source.prototype = temp;
}
// 父类:Car
function Car(name, type, date) {
this.name = name;
this.type = type;
this.productionDate = date;
}
Car.prototype.run = function() {
console.log(`${this.name} is runing`);
}
// 子类:Benz
function Benz(name, type, date) {
Car.call(this, name, type, date)
}
// 实现继承
inheritProtoType(Benz, Car);
Benz.prototype.drive = function() {
console.log(`${this.name} is by drived`)
}
// 子类:Benz
function BMW(name, type, date) {
Car.call(this, name, type, date)
}
// 实现继承
inheritProtoType(BMW, Car);
})()
ES6实现继承
如果使用 ES6 来实现以上的继承,代码大致修改如下:
class Car {
constructor(name, type, date) {
this.name = name;
this.type = type;
this.productionDate = date;
}
run() {
console.log(`${this.name} is runing`);
}
}
class Benz extends Car {
constructor(name, type, date) {
super(name, type, date);
}
drive() {
console.log(`${this.name} is by drived`)
}
}
class BMW extends Car {
constructor(name, type, date) {
super(name, type, date);
}
}
这其中有几个关键字:class、expends、constructor、super。ES6的写法简洁方便了很多。那如果通过 Babel 编译之后,编译出来的代码跟我们自己实现的 ES5 继承的代码相差多少呢?
Babel 编译过后的 ES6 实现继承的代码
本来想隐藏代码结果的。但是隐藏之后代码无法高亮。ES6 实现继承的方式通过 Babel 编译之后的结果明显比我们自己实现的多了很多代码。我们自己实现的代码50行,编译出来的有130行左右。因为我们自己写的代码未考虑兼容性、健壮性的问题。很多地方的实现值得学习,其中代码注释写了一些自己理解存疑的疑问点。
(function (factory) {
typeof define === 'function' && define.amd ? define(factory) :
factory();
}((function () { 'use strict';
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof 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;
}
/**
* 跟我们实现的继承方式相差无几,只是使用了 Object.create 来实现。
* 同时还考虑了浏览器兼容性问题
* @param {*} subClass
* @param {*} superClass
*/
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 _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
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 _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _possibleConstructorReturn(self, call) {
if (call && (typeof call === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
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);
};
}
var Car = /*#__PURE__*/function () {
function Car(name, type, date) {
_classCallCheck(this, Car);
this.name = name;
this.type = type;
this.productionDate = date;
}
/*
ES5 里的写法 Car.prototype.run = function() {};
本质是往原型上添加run方法。那为何不直接使用 Car.prototype.run 呢?
*/
_createClass(Car, [{
key: "run",
value: function run() {
console.log("".concat(this.name, " is runing"));
}
}]);
return Car;
}();
var Benz = /*#__PURE__*/function (_Car) {
// 实现继承
_inherits(Benz, _Car);
var _super = _createSuper(Benz);
function Benz(name, type, date) {
_classCallCheck(this, Benz);
// 调用父类的构造函数,传递参数.为何不直接调用 _Car.call()?
return _super.call(this, name, type, date);
}
_createClass(Benz, [{
key: "drive",
value: function drive() {
console.log("".concat(this.name, " is by drived"));
}
}]);
return Benz;
}(Car);
var BMW = /*#__PURE__*/function (_Car2) {
_inherits(BMW, _Car2);
var _super2 = _createSuper(BMW);
function BMW(name, type, date) {
_classCallCheck(this, BMW);
return _super2.call(this, name, type, date);
}
return BMW;
}(Car);
var benz = new Benz('Benz', '4drive', '20201010');
var bmw = new BMW('BMW', '2drive', '20201111');
benz.run();
bmw.run();
benz.drive();
})));