ES6 在 JavaScript 中引入了“类”的概念,这与其他编程语言中的类不同。在此,类是充当模板的特殊函数,用于创建已包含数据、与该数据关联的属性以及与该数据的操作相关的方法的对象。这些对象、属性和方法统称为类的“成员”。

要定义类,请使用 class 关键字。按照最佳实践和 JavaScript 内置构造函数建立的约定,以大写字母开头作为类的任何标识符

class MyClass {}

类的目的在于提供更易于访问的方式来使用原型和构造函数的进阶功能

class MyClass {}

typeof MyClass;
> "function"

由于添加类部分是为了让使用 JavaScript 进阶功能更轻松且更具吸引力,因此它们有时被称为“语法糖”。但是,类的作用不仅仅是为使用原型继承提供有用的简写。引入类语法创造了解决 JavaScript 中长期存在的设计问题的机会,而不会引入向后兼容性问题。例如,类主体内的所有代码始终在严格模式下进行评估。

要创建类的实例,请使用 new 运算符。

class MyClass {}

const myClassInstance = new MyClass();

myClassInstance;
> Object { }

在类主体内定义的函数会公开为该类每个实例的方法。

class MyClass {
    classMethod() {
        console.log( "My class method." );
    }
}

const myClassInstance = new MyClass();

myClassInstance.classMethod();
> "My class method."

在类中定义的方法将成为结果实例原型上的方法。由于原型链的性质,您可以直接在结果对象上调用这些方法

class MyClass {
  classMethod() {
    console.log( "My class method." );
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance;
> Object { }
    <prototype>: Object {  }
        classMethod: function classMethod()
        constructor: class MyClass { constructor(myPassedValue) }
        <prototype>: Object {  }

myClassInstance.classMethod();
> "My class method."

创建类的实例会调用特殊的 constructor() 方法,该方法对新创建的实例执行任何必要的“设置”,并初始化与其关联的任何属性。创建实例时传递给类的任何参数都可供 constructor() 方法使用

class MyClass {
  constructor( myPassedValue ) {
    console.log( myPassedValue );
  }
}

const myClassInstance = new MyClass( "A string." );
> "A string."

在类主体中,this 的值指的是实例本身,在 this 上定义的任何属性都将公开为该类每个实例的属性

class MyClass {
  constructor( myPassedValue ) {
    this.instanceProperty = myPassedValue;
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance;
> Object { instanceProperty: "A string." }

这些属性也适用于类主体内的所有方法

class MyClass {
  constructor( myPassedValue ) {
    this.instanceProp = myPassedValue;
  }
  myMethod() {
    console.log( this.instanceProp );
  }
}

const myClassInstance = new MyClass( "A string." );

myClassInstance.myMethod();
> "A string."

如果您没有为类定义 constructor(),则 JavaScript 引擎会假定为空的“默认”constructor。每个类只能有一个名为 constructor() 的特殊方法

class MyClass {
  constructor() {}
  constructor() {}
}
> Uncaught SyntaxError: A class may only have one constructor

您可以使用类声明类表达式来定义类。之前的示例都是类声明,类声明需要使用 new 调用名称。类表达式可以命名或保持未命名以创建“匿名”类。

let ClassExpression = class {
    constructor() {}
};

ClassExpression;
> class  {}

您可以使用匿名类表达式的一种用途是动态构造类的函数:

function classMaker() {
  return class {
    constructor() {}
  };
}

let MyVariable = classMaker();

MyVariable;
> class  {}

使用类声明重新声明类会导致语法错误


class MyClass {
    constructor( ) {
        console.log( "My class." );
    }
};

class MyClass {
    constructor() {
        console.log( "My new class." );
    }
};
> Uncaught SyntaxError: redeclaration of class MyClass

但是,类表达式允许您重新定义类

let ClassExpression = class MyClass { };

ClassExpression = class MyOtherClass {
    constructor( myString ) {
        this.myProp = myString;
    }
};

new ClassExpression( "String." );
> MyOtherClass {myProp: 'String.'}

您无法像调用类声明那样按名称调用命名的类表达式。但是,类表达式的分配名称可用作已创建实例的属性,主要用于使调试更轻松

let MyVariable = class MyClass {};

MyClass;
> Uncaught ReferenceError: MyClass is not defined

MyVariable;
> class MyClass {}

MyVariable.name;
> "MyClass"

当您使用类表达式初始化变量时,将按照该变量的提升规则进行操作。类声明遵循与 letconst 相同的“暂时性死区”规则,并且其行为就好像它们尚未提升到其当前作用域的顶部一样,这意味着在类声明之前调用类会导致错误

{
    let myVar = new MyClass( "Property string." );

    class MyClass {
        myProp;

        constructor( myString ) {
            this.myProp = myString;
        }
    };
};
> Uncaught ReferenceError: Cannot access 'MyClass' before initialization

检查您的理解程度

以下哪项正确定义了类?

class MyClass {}
myClass = class {}
new class()

一个类可以有多少个 constructor() 方法?

一个
不限