使用最多的模式是组合继承:原型链继承共享的属性和方法,借用构造函数继承实例属性。
最简单的类
class A {}
Babel转换后
"use strict";
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var A = function A() {
_classCallCheck(this, A);
};
_classCallCheck()
函数内部,判断this
是否为Constructor
的实例,目的是创建作用域安全的构造函数,防止构造函数被当成普通函数调用。例如A()
调用,this
会指向其他对象,于是_classCallCheck()
函数抛出错误。
用函数关键字定义A
,再把函数赋值给变量A
。这个过程需要指出的是,函数关键字后的标识符A
并非变量A
,只能在函数内部引用。
用匿名函数赋值,而不是函数关键字定义函数,是为了让ES6 class不产生定义提前。
类的基本继承
class A {};
class B extends A {};
转换后
"use strict";
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 A = function A() {
_classCallCheck(this, A);
};
var B = function(_A) {
_inherits(B, _A);
function B() {
_classCallCheck(this, B);
return _possibleConstructorReturn(this, (B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments));
}
return B;
}(A);
_inherits()
函数主要做了两件事:
- 让子类构造函数
prototype
的原型指向超类构造函数prototype
,实现实例属性共享 - 让子类构造函数的原型指向超类构造函数,实现类属型方法共享
Object.create()
方法,接受第二个参数用于重写属性描述。在babel转换的代码中,constructor
属性被重新配置成了不可枚举。
Object.setPrototypeOf()
方法,可直接将指定对象的原型设为另一个对象或者null
。但该新特性属于ES6,使用时注意浏览器兼容性。
(B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments)
此处借调超类的构造函数,完成子类实例的初始化。