类表达式
类与函数有相似之处,即它们都有两种形式:声明与表达式。函数声明与类声明都以适当的关键词为起始(分别是 function
与 class
),随后是标识符(即函数名或类名)。函数具有一种表达式形式,无须在 function
后面使用标识符;类似的,类也有不需要标识符的表达式形式。类表达式被设计用于变量声明,或可作为参数传递给函数。
基本的类表达式
此处是与上例中的 PersonClass
等效的类表达式,随后的代码使用了它:
let PersonClass = class {
// equivalent of the PersonType constructor
constructor(name) {
this.name = name;
}
// equivalent of PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
};
let person = new PersonClass("Nicholas");
person.sayName(); // outputs "Nicholas"
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"
javascript
正如此例所示,类表达式不需要在 class
关键字后使用标识符。除了语法差异,类表达式的功能等价于类声明。
使用类声明还是类表达式,主要是代码风格问题。相对于函数声明与函数表达式之间的区别,类声明与类表达式都不会被提升,因此对代码运行时的行为影响甚微。 |
具名类表达式
上一节的示例使用了一个匿名的类表达式,不过就像函数表达式那样,你也可以为类表达式命名。为此需要在 class
关键字后添加标识符,就像这样:
let PersonClass = class PersonClass2 {
// equivalent of the PersonType constructor
constructor(name) {
this.name = name;
}
// equivalent of PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
};
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass2); // "undefined"
javascript
此例中的类表达式被命名为 PersonClass2
。PersonClass2
标识符只在类定义内部存在,因此只能用在类方法内部(例如本例的 sayName()
内)。在类的外部,typeof PersonClass2
的结果为 "undefined"
,这是因为外部不存在 PersonClass2
绑定。要理解为何如此,请查看未使用类语法的等价声明:
// direct equivalent of PersonClass named class expression
let PersonClass = (function() {
"use strict";
const PersonClass2 = function(name) {
// make sure the function was called with new
if (typeof new.target === "undefined") {
throw new Error("Constructor must be called with new.");
}
this.name = name;
}
Object.defineProperty(PersonClass2.prototype, "sayName", {
value: function() {
// make sure the method wasn't called with new
if (typeof new.target !== "undefined") {
throw new Error("Method cannot be called with new.");
}
console.log(this.name);
},
enumerable: false,
writable: true,
configurable: true
});
return PersonClass2;
}());
javascript
创建具名的类表达式稍微改变了在 JS
引擎内部发生的事。对于类声明来说,外部绑定(用 let
定义)与内部绑定(用 const
定义)有着相同的名称。而类表达式可在内部使用 const
来定义它的不同名称,因此此处的 PersonClass2
只能在类的内部使用。
尽管具名类表达式的行为异于具名函数表达式,但它们之间仍然有许多相似点。二者都能被当作值来使用,这开启了许多可能性,接下来我将会对此进行介绍。