ES6学习笔记2:Class关键字

Class关键字

在ES5中,不同于Java等面向对象语言,由于没有真正的类的概念存在,常采用基于原型的面向对象(Prototype based OO)来实现面向对象的逻辑。Babel官网将ES6中的class关键字称为语法糖(Syntactic Sugar)。ES6中的class支持基于原型的继承,super方法调用,创建实例,静态方法,以及构造方法。

ES6代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class SkinnedMesh extends THREE.Mesh {
constructor(geometry, materials) {
super(geometry, materials);
this.idMatrix = SkinnedMesh.defaultMatrix();
this.bones = [];
this.boneMatrices = [];
}
update(camera) {
super.update();
}
static defaultMatrix() {
return new THREE.Matrix4();
}
}

上述代码定义了一个继承自THREE.Mesh的SkinnedMesh类,构造方法中有两个参数,此外共有三个属性,一个名为update的成员方法和一个名为defaultMatrix的静态方法。

使用Babel编译后的ES5代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
"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; }; }();
// 用于获取父类中的方法
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; 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); } };
// 检查instance是否被当做Constructor类型在被使用
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
// 模拟构造器返回类实例中的当前对象
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; }
var SkinnedMesh = function (_THREE$Mesh) {
_inherits(SkinnedMesh, _THREE$Mesh);
function SkinnedMesh(geometry, materials) {
_classCallCheck(this, SkinnedMesh);
var _this = _possibleConstructorReturn(this, (SkinnedMesh.__proto__ || Object.getPrototypeOf(SkinnedMesh)).call(this, geometry, materials));
_this.idMatrix = SkinnedMesh.defaultMatrix();
_this.bones = [];
_this.boneMatrices = [];
return _this;
}
_createClass(SkinnedMesh, [{
key: "update",
value: function update(camera) {
_get(SkinnedMesh.prototype.__proto__ || Object.getPrototypeOf(SkinnedMesh.prototype), "update", this).call(this);
}
}], [{
key: "defaultMatrix",
value: function defaultMatrix() {
return new THREE.Matrix4();
}
}]);
return SkinnedMesh;
}(THREE.Mesh);

继承和原型链

ES6的class关键字是定义类的语法糖,底层关于class关键字的实现也是用过基于原型实现的。关于继承和原型链,不属于本文的讨论的内容,这里只介绍class关键字最基本的用法。

想要了解继承和原型链,参考2是一篇详细而基础的文档,此外笔者后续也会写一篇关于原型链的总结。

知识点总结

  1. 使用class关键字定义类,继承父类,构造器,super方法,静态方法,以及创建实例;
  2. 知道ES6中的class仍然只是JS原型链的语法糖。

参考

  1. BabelJS - Learn ES2015
  2. Inheritance and the prototype chain - MDN