类是用于创建对象的模板。他们用代码封装数据以处理该数据。 JS中的类建立在原型上,但也具有某些语法和语义未与ES5类相似语义共享。

定义

实际上,类是“特殊的函数”,就像你能够定义的函数表达式函数声明一样,类语法有两个组成部分:类表达式类声明

类声明

定义类的一种方法是使用类声明。要声明一个类,你可以使用带有class关键字的类名(这里是“Rectangle”)。

  1. class Rectangle {
  2. constructor(height, width) {
  3. this.height = height;
  4. this.width = width;
  5. }
  6. }

提升

函数声明类声明之间的一个重要区别在于, 函数声明会提升,类声明不会。你首先需要声明你的类,然后再访问它,否则类似以下的代码将抛出ReferenceError

  1. let p = new Rectangle(); // ReferenceError
  2. class Rectangle {}

类表达式

类表达式是定义类的另一种方法。类表达式可以命名或不命名。命名类表达式的名称是该类体的局部名称。(不过,可以通过类的(而不是一个实例的) name 属性来检索它)。

  1. // 未命名/匿名类
  2. let Rectangle = class {
  3. constructor(height, width) {
  4. this.height = height;
  5. this.width = width;
  6. }
  7. };
  8. console.log(Rectangle.name);
  9. // output: "Rectangle"
  10. // 命名类
  11. let Rectangle = class Rectangle2 {
  12. constructor(height, width) {
  13. this.height = height;
  14. this.width = width;
  15. }
  16. };
  17. console.log(Rectangle.name);
  18. // 输出: "Rectangle2"

类体和方法定义

一个类的类体是一对花括号/大括号 {} 中的部分。这是你定义类成员的位置,如方法或构造函数。

严格模式

类声明和类表达式的主体都执行在严格模式下。比如,构造函数,静态方法,原型方法,getter和setter都在严格模式下执行。

构造函数

constructor方法是一个特殊的方法,这种方法用于创建和初始化一个由class创建的对象。一个类只能拥有一个名为 “constructor”的特殊方法。如果类包含多个constructor的方法,则将抛出 一个SyntaxError
一个构造函数可以使用 super 关键字来调用一个父类的构造函数。

原型方法

参见方法定义

  1. class Rectangle {
  2. // constructor
  3. constructor(height, width) {
  4. this.height = height;
  5. this.width = width;
  6. }
  7. // Getter
  8. get area() {
  9. return this.calcArea()
  10. }
  11. // Method
  12. calcArea() {
  13. return this.height * this.width;
  14. }
  15. }
  16. const square = new Rectangle(10, 10);
  17. console.log(square.area);

静态方法

[static](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/static) 关键字用来定义一个类的一个静态方法。调用静态方法不需要实例化)该类,但不能通过一个类实例调用静态方法。静态方法通常用于为一个应用程序创建工具函数。

  1. class Point {
  2. constructor(x, y) {
  3. this.x = x;
  4. this.y = y;
  5. }
  6. static distance(a, b) {
  7. const dx = a.x - b.x;
  8. const dy = a.y - b.y;
  9. return Math.hypot(dx, dy);
  10. }
  11. }
  12. const p1 = new Point(5, 5);
  13. p1.displayName;
  14. // undefined
  15. p1.distance;
  16. // undefined
  17. console.log(Point.displayName);
  18. // "Point"
  19. console.log(Point.distance(p1, p2));
  20. // 7.0710678118654755

用原型和静态方法绑定 this

当调用静态或原型方法时没有指定 this 的值,那么方法内的 this 值将被置为 undefined。即使你未设置 “use strict” ,因为 class 体内部的代码总是在严格模式下执行。

  1. class Animal {
  2. speak() {
  3. return this;
  4. }
  5. static eat() {
  6. return this;
  7. }
  8. }
  9. let obj = new Animal();
  10. obj.speak(); // Animal {}
  11. let speak = obj.speak;
  12. speak(); // undefined
  13. Animal.eat() // class Animal
  14. let eat = Animal.eat;
  15. eat(); // undefined

如果上述代码通过传统的基于函数的语法来实现,那么依据初始的 this 值,在非严格模式下方法调用会发生自动装箱。若初始值是 undefinedthis 值会被设为全局对象。
严格模式下不会发生自动装箱,this 值将保留传入状态。

  1. function Animal() { }
  2. Animal.prototype.speak = function() {
  3. return this;
  4. }
  5. Animal.eat = function() {
  6. return this;
  7. }
  8. let obj = new Animal();
  9. let speak = obj.speak;
  10. speak(); // global object
  11. let eat = Animal.eat;
  12. eat(); // global object

实例属性

实例的属性必须定义在类的方法里:

  1. class Rectangle {
  2. constructor(height, width) {
  3. this.height = height;
  4. this.width = width;
  5. }
  6. }

静态的或原型的数据属性必须定义在类定义的外面。

  1. Rectangle.staticWidth = 20;
  2. Rectangle.prototype.prototypeWidth = 25;

字段声明

公共和私有字段声明是JavaScript标准委员会TC39提出的实验性功能(第3阶段)。浏览器中的支持是有限的,但是可以通过Babel等系统构建后使用此功能。

公有字段声明

使用JavaScript字段声明语法,上面的示例可以写成:

  1. class Rectangle {
  2. height = 0;
  3. width;
  4. constructor(height, width) {
  5. this.height = height;
  6. this.width = width;
  7. }
  8. }

通过预先声明字段,类定义变得更加自我记录,并且字段始终存在。
正如上面看到的,这个字段可以用也可以不用默认值来声明。

私有字段声明

使用私有字段,可以按以下方式细化定义。

  1. class Rectangle {
  2. #height = 0;
  3. #width;
  4. constructor(height, width) {
  5. this.#height = height;
  6. this.#width = width;
  7. }
  8. }

从类外部引用私有字段是错误的。它们只能在类里面中读取或写入。通过定义在类外部不可见的内容,可以确保类的用户不会依赖于内部,因为内部可能在不同版本之间发生变化。
私有字段仅能在字段声明中预先定义。
私有字段不能通过在之后赋值来创建它们,这种方式只适用普通属性。
更多信息,请看class fields.

extends

[extends](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/extends) 关键字在 类声明 类表达式 中用于创建一个类作为另一个类的一个子类。

  1. class Animal {
  2. constructor(name) {
  3. this.name = name;
  4. }
  5. speak() {
  6. console.log(`${this.name} makes a noise.`);
  7. }
  8. }
  9. class Dog extends Animal {
  10. constructor(name) {
  11. super(name); // 调用超类构造函数并传入name参数
  12. }
  13. speak() {
  14. console.log(`${this.name} barks.`);
  15. }
  16. }
  17. var d = new Dog('Mitzie');
  18. d.speak();// 'Mitzie barks.'