学习ECMAScript 2015【2】Classes

0. 前言

其实类这个概念,最早在C++出现,Java发扬光大。JS之前也写类,根据文章:JavaScript 定义类的最佳写法——完整支持面向对象(封装、继承、多态),兼容所有浏览器,支持用JSDuck生成文档中的示例,之前的基本长这样:

function PersonInfo() {
    // 自身的实例字段.
    this.name = "";    // 姓名.
    this.gender = 0;    // 性别. 0未知, 1男, 2女.
}

那出现单独的关键字好不好呢?当然好了,更加清晰了,现在看大神们写的ts文件里到处都是接口、类,写得很顺。雷峰塔越来越像雷锋,也不是个坏事。

学习ECMAScript 2015【2】Classes

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太灵活了,后边声明也行,怪不得大家喜欢。

可是这事儿也不都是好事儿,灵活的另一面就是乱写。越是约束多的代码,大家阅读起来就越顺眼,反正五五开吧。就比方说,有人就是把逻辑全写前面的一个函数里,看的时候,一大堆函数都在后面。就好像一个武林高手,虽只用一个招式,但内力无穷。

学习ECMAScript 2015【2】Classes

现在我看到大家更喜欢写写写,最后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"

getter
setter

2.4.扩展阅读

MDN Web Docs 中还给出了一些不常用的,例如species 帮助你覆盖父类的构造方法Mix-ins / 混入最好是遇到了再对照,感觉例子给出来之后也不是很明白啥时候能用。

3.结语

好了,这就是对于ES2015类的部分的介绍,我的感受是一句话:

学习ECMAScript 2015【2】Classes
学习ECMAScript 2015【2】Classes
学习ECMAScript 2015【2】Classes
学习ECMAScript 2015【2】Classes

上一篇:EFCore学习(二)——添加,修改,删除,查询操作及将EFCore语句编译成sql


下一篇:windows动态磁铁设置