0. 前言
其实类这个概念,最早在C++出现,Java发扬光大。JS之前也写类,根据文章:JavaScript 定义类的最佳写法——完整支持面向对象(封装、继承、多态),兼容所有浏览器,支持用JSDuck生成文档中的示例,之前的基本长这样:
function PersonInfo() {
// 自身的实例字段.
this.name = ""; // 姓名.
this.gender = 0; // 性别. 0未知, 1男, 2女.
}
那出现单独的关键字好不好呢?当然好了,更加清晰了,现在看大神们写的ts文件里到处都是接口、类,写得很顺。雷峰塔越来越像雷锋,也不是个坏事。
1.Class
简言之,之前没有,写得不好看,现在补上。支持基于原型的继承,调用父类的方法,构造器、静态方法等,这么多语法,我们先看一个示例,熟悉一下:
class SkinnedMesh extends THREE.Mesh {
constructor(geometry, materials) {// 这里注意,构造器的名字可不是类名,统一叫 constructor
super(geometry, materials); // 父类构造方法
this.idMatrix = SkinnedMesh.defaultMatrix();// 这里调用静态方法用的是类名.方法,和Java中推荐的一样
this.bones = [];
this.boneMatrices = [];
}
update(camera) {
super.update();// 调用父类方法
}
static defaultMatrix() {
return new THREE.Matrix4();// 新建就new
}
}
P.S.:本人不喜欢行尾注释,故在他的代码中添加行尾注释以说明特点
2.更多示例
2.1. 注意变量提升问题
Hoisting(变量提升)是Javascript中执行上下文 (特别是创建和执行阶段)工作方式的一种认识。“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,但这么说并不准确。实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中。简单说:你可以在声明一个函数之前使用该函数。 这个变量提升特性很牛的,我之前敲JS的时候就常常感叹,JS太灵活了,后边声明也行,怪不得大家喜欢。
可是这事儿也不都是好事儿,灵活的另一面就是乱写。越是约束多的代码,大家阅读起来就越顺眼,反正五五开吧。就比方说,有人就是把逻辑全写前面的一个函数里,看的时候,一大堆函数都在后面。就好像一个武林高手,虽只用一个招式,但内力无穷。
现在我看到大家更喜欢写写写,最后export
了,当然了,仁者见仁智者见智。
值得注意的是,类的声明,可没有变量提升,您要守规矩,不能乱写的,像下面的代码就是错的!
// 错误代码示例
let p = new Rectangle(); // ReferenceError
class Rectangle {}
2.2.不能通过一个类实例调用静态方法
JS和Java有所不同,例如下面的例子告诉我们,不能用实例调用静态方法。静态方法通常用来为一个应用程序创建工具函数 ,也就是咱们常说的工具类中的方法。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static displayName = "Point";
static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
}
const p1 = new Point(5, 5);
const p2 = new Point(10,10);
p1.displayName;
// undefined
p1.distance;
// undefined
console.log(Point.displayName);
// "Point"
console.log(Point.distance(p1, p2));
// 7.0710678118654755
2.3.字段声明
2.3.1.公有字段声明
class Rectangle {
height = 0; // 你还可以指定默认值
width;
constructor(height, width) {
this.height = height;
this.width = width;
}
}
2.3.2.私有字段声明
class Rectangle {
#height = 0;
#width;
constructor(height, width) {
this.#height = height;
this.#width = width;
}
}
从类外部引用私有字段是错误的。它们只能在类里面中读取或写入。通过定义在类外部不可见的内容,可以确保类的用户不会依赖于内部,因为内部可能在不同版本之间发生变化。
你也许会问了,那getter setter
我咋写?这样写:
class ClassWithGetSet {
#msg = 'hello world'
get msg() {
return this.#msg
}
set msg(x) {
this.#msg = `hello ${x}`
}
}
const instance = new ClassWithGetSet()
console.log(instance.msg)
// expected output: "hello world"
instance.msg = 'cake'
console.log(instance.msg)
// expected output: "hello cake"
2.4.扩展阅读
MDN Web Docs
中还给出了一些不常用的,例如species 帮助你覆盖父类的构造方法、Mix-ins / 混入最好是遇到了再对照,感觉例子给出来之后也不是很明白啥时候能用。
3.结语
好了,这就是对于ES2015类的部分的介绍,我的感受是一句话: