其实类这个概念,最早在C++出现,Java发扬光大。JS之前也写类,根据文章:JavaScript 定义类的最佳写法——完整支持面向对象(封装、继承、多态),兼容所有浏览器,支持用JSDuck生成文档中的示例,之前的基本长这样:
function PersonInfo() { // 自身的实例字段. this.name = ""; // 姓名. this.gender = 0; // 性别. 0未知, 1男, 2女. }
那出现单独的关键字好不好呢?当然好了,更加清晰了,现在看大神们写的ts文件里到处都是接口、类,写得很顺。雷峰塔越来越像雷锋,也不是个坏事。
简言之,之前没有,写得不好看,现在补上。支持基于原型的继承,调用父类的方法,构造器、静态方法等,这么多语法,我们先看一个示例,熟悉一下:
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.:本人不喜欢行尾注释,故在他的代码中添加行尾注释以说明特点
Hoisting(变量提升)是Javascript中执行上下文 (特别是创建和执行阶段)工作方式的一种认识。“变量提升”意味着变量和函数的声明会在物理层面移动到代码的最前面,但这么说并不准确。实际上变量和函数声明在代码里的位置是不会动的,而是在编译阶段被放入内存中。简单说:你可以在声明一个函数之前使用该函数。 这个变量提升特性很牛的,我之前敲JS的时候就常常感叹,JS太灵活了,后边声明也行,怪不得大家喜欢。
可是这事儿也不都是好事儿,灵活的另一面就是乱写。越是约束多的代码,大家阅读起来就越顺眼,反正五五开吧。就比方说,有人就是把逻辑全写前面的一个函数里,看的时候,一大堆函数都在后面。就好像一个武林高手,虽只用一个招式,但内力无穷。
现在我看到大家更喜欢写写写,最后export
了,当然了,仁者见仁智者见智。
值得注意的是,类的声明,可没有变量提升,您要守规矩,不能乱写的,像下面的代码就是错的!
// 错误代码示例 let p = new Rectangle(); // ReferenceError class Rectangle {}
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
class Rectangle { height = 0; // 你还可以指定默认值 width; constructor(height, width) { this.height = height; this.width = width; } }
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"
getter
setter
MDN Web Docs
中还给出了一些不常用的,例如species 帮助你覆盖父类的构造方法、Mix-ins / 混入最好是遇到了再对照,感觉例子给出来之后也不是很明白啥时候能用。
好了,这就是对于ES2015类的部分的介绍,我的感受是一句话: