类可能有静态成员。 这些成员与类的特定实例无关。 它们可以通过类构造函数对象本身访问:
class MyClass {
static x = 0;
static printX() {
console.log(MyClass.x);
}
}
console.log(MyClass.x);
MyClass.printX();
Special Static Names
有一些特殊的名称,不能用于 TypeScript class 的静态成员变量定义。
从 Function 原型中覆盖属性通常是不安全/不可能的。 因为类本身就是可以用 new 调用的函数,所以不能使用某些静态名称。 名称、长度和调用等函数属性不能定义为静态成员:
class S {
static name = "S!";
Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'S'.
}
Generic Classes
类,很像接口,可以是通用的。 当使用 new 实例化泛型类时,其类型参数的推断方式与函数调用中的推断方式相同:
class Box<Type> {
contents: Type;
constructor(value: Type) {
this.contents = value;
}
}
const b = new Box("hello!");
const b: Box<string>
Type Parameters in Static Members
下列代码会出现语法错误:
class Box<Type> {
static defaultValue: Type;
Static members cannot reference class type parameters.
}
请记住,类型总是被完全擦除! 在运行时,只有一个 Box.defaultValue 属性槽。 这意味着设置 Box<string>.defaultValue (如果可能的话)也会改变 Box<number>.defaultValue - 不好。 泛型类的静态成员永远不能引用类的类型参数。
this at Runtime in Classes
重要的是要记住 TypeScript 不会改变 JavaScript 的运行时行为,而且 JavaScript 以具有一些特殊的运行时行为而闻名。
JavaScript 对此的处理确实不同寻常:
class MyClass {
name = "MyClass";
getName() {
return this.name;
}
}
const c = new MyClass();
const obj = {
name: "obj",
getName: c.getName,
};
// Prints "obj", not "MyClass"
console.log(obj.getName());
长话短说,默认情况下,函数内 this 的值取决于函数的调用方式。 在这个例子中,因为函数是通过 obj 引用调用的,所以它的 this 值是 obj 而不是类实例。
这很少是你想要发生的! TypeScript 提供了一些方法来减轻或防止这种错误。
方法1 - 使用箭头函数
如果您有一个经常以丢失 this 上下文的方式调用的函数,则使用箭头函数属性而不是方法定义是有意义的:
class MyClass {
name = "MyClass";
getName = () => {
return this.name;
};
}
const c = new MyClass();
const g = c.getName;
// Prints "MyClass" instead of crashing
console.log(g());
这有一些权衡:
- 即使对于未使用 TypeScript 检查的代码,此值也保证在运行时是正确的
- 这将使用更多内存,因为每个类实例都有自己的以这种方式定义的每个函数的副本
- 不能在派生类中使用 super.getName,因为原型链中没有条目可以从中获取基类方法
网友评论