公有字段
静态公有字段和实例公有字段都是可编辑的,可遍历的,可配置的。它们本身不同于私有对应值(private counterparts)的是,它们参与原型的继承。
静态公有字段
静态公有字段在你想要创建一个只在每个类里面只存在一份,而不会存在于你创建的每个类的实例中的属性时可以用到。你可以用它存放缓存数据、固定结构数据或者其他你不想在所有实例都复制一份的数据。
静态公有字段是使用关键字 static
声明的。我们在声明一个类的时候,使用Object.defineProperty方法将静态公有字段添加到类的构造函数中。在类被声明之后,可以从类的构造函数访问静态公有字段。
class ClassWithStaticField { static staticField = 'static field'; } console.log(ClassWithStaticField.staticField); // 预期输出值: "static field"
没有设定初始化程序的字段将默认被初始化为undefined
。
class ClassWithStaticField { static staticField; } console.assert(ClassWithStaticField.hasOwnProperty('staticField')); console.log(ClassWithStaticField.staticField); // 预期输出值: "undefined"
静态公有字段不会在子类里重复初始化,但我们可以通过原型链访问它们。
class ClassWithStaticField { static baseStaticField = 'base field'; } class SubClassWithStaticField extends ClassWithStaticField { static subStaticField = 'sub class field'; } console.log(SubClassWithStaticField.subStaticField); // 预期输出值: "sub class field" console.log(SubClassWithStaticField.baseStaticField); // 预期输出值: "base field"
当初始化字段时,this
指向的是类的构造函数。你可以通过名字引用构造函数,并使用super
获取到存在的超类构造函数。
class ClassWithStaticField { static baseStaticField = 'base static field'; static anotherBaseStaticField = this.baseStaticField; static baseStaticMethod() { return 'base static method output'; } } class SubClassWithStaticField extends ClassWithStaticField { static subStaticField = super.baseStaticMethod(); } console.log(ClassWithStaticField.anotherBaseStaticField); // 预期输出值: "base static field" console.log(SubClassWithStaticField.subStaticField); // 预期输出值: "base static method output"
公有实例字段
公有实例字段存在于类的每一个实例中。通过声明一个公有字段,我们可以确保该字段一直存在,而类的定义则会更加像是自我描述。
公有实例字段可以在基类的构造过程中(构造函数主体运行前)使用Object.defineProperty添加,也可以在子类构造函数中的super()
函数结束后添加。
class ClassWithInstanceField { instanceField = 'instance field'; } const instance = new ClassWithInstanceField(); console.log(instance.instanceField); // 预期输出值: "instance field"
没有设定初始化程序的字段将默认被初始化为undefined
。
class ClassWithInstanceField { instanceField; } const instance = new ClassWithInstanceField(); console.assert(instance.hasOwnProperty('instanceField')); console.log(instance.instanceField); // 预期输出值: "undefined"
和属性(properties)一样,字段名可以由计算得出。
const PREFIX = 'prefix'; class ClassWithComputedFieldName { [`${PREFIX}Field`] = 'prefixed field'; } const instance = new ClassWithComputedFieldName(); console.log(instance.prefixField); // 预期输出值: "prefixed field"
当初始化字段时,this
指向的是类正在构造中的实例。和公共实例方法相同的是:你可以在子类中使用super
来访问超类的原型。
class ClassWithInstanceField { baseInstanceField = 'base field'; anotherBaseInstanceField = this.baseInstanceField; baseInstanceMethod() { return 'base method output'; } } class SubClassWithInstanceField extends ClassWithInstanceField { subInstanceField = super.baseInstanceMethod(); } const base = new ClassWithInstanceField(); const sub = new SubClassWithInstanceField(); console.log(base.anotherBaseInstanceField); // 预期输出值: "base field" console.log(sub.subInstanceField); // 预期输出值: "base method output"
公共方法
静态公共方法
关键字static
将为一个类定义一个静态方法。静态方法不会在实例中被调用,而只会被类本身调用。它们经常是工具函数,比如用来创建或者复制对象。
这些交互案例的资源储存在GitHub仓库中。如果你想参与这个项目,请复制链接https://github.com/mdn/interactive-examples并向我们发送拉取(pull)请求。
静态方法是在类的赋值阶段用Object.defineProperty方法添加到类中的。静态方法是可编辑的、不可遍历的和可配置的。
公共实例方法
正如其名,公共实例方法是可以在类的实例中使用的。
class ClassWithPublicInstanceMethod { publicMethod() { return 'hello world'; } } const instance = new ClassWithPublicInstanceMethod(); console.log(instance.publicMethod()); // 预期输出值: "hello world"
公共实例方法是在类的赋值阶段用Object.defineProperty方法添加到类中的。静态方法是可编辑的、不可遍历的和可配置的。
你可以使用生成器(generator)、异步和异步生成器方法。
class ClassWithFancyMethods { *generatorMethod() { } async asyncMethod() { } async *asyncGeneratorMethod() { } }
在实例的方法中,this
指向的是实例本身,你可以使用super
访问到超类的原型,由此你可以调用超类的方法。
class BaseClass { msg = 'hello world'; basePublicMethod() { return this.msg; } } class SubClass extends BaseClass { subPublicMethod() { return super.basePublicMethod(); } } const instance = new SubClass(); console.log(instance.subPublicMethod()); // 预期输出值: "hello world"
getter
和setter
是和类的属性绑定的特殊方法,分别会在其绑定的属性被取值、赋值时调用。使用get和set句法定义实例的公共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); // 预期输出值: "hello cake"
私有字段
静态私有字段
静态私有字段可以在类声明本身内部的构造函数上被访问到。
静态变量只能被静态方法访问的限制依然存在。
class ClassWithPrivateStaticField { static #PRIVATE_STATIC_FIELD; static publicStaticMethod() { ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD = 42; return ClassWithPrivateStaticField.#PRIVATE_STATIC_FIELD; } } assert(ClassWithPrivateStaticField.publicStaticMethod() === 42);
静态私有字段是在类赋值的时候被添加到类构造函数中的。
静态私有字段有一个来源限制。只有定义静态私有字段的类可以访问该字段。这在使用this
时,可能会导致不符合预期的行为。
class BaseClassWithPrivateStaticField { static #PRIVATE_STATIC_FIELD; static basePublicStaticMethod() { this.#PRIVATE_STATIC_FIELD = 42; return this.#PRIVATE_STATIC_FIELD; } } class SubClass extends BaseClassWithPrivateStaticField { } assertThrows(() => SubClass.basePublicStaticMethod(), TypeError);
私有实例字段
私有实例字段是通过# names句型(读作“哈希名称”)声明的,即为识别符加一个前缀“#”。“#”是名称的一部分,也用于访问和声明。
封装是语言强制实施的。引用不在作用域内的 # names 是语法错误。
class ClassWithPrivateField { #privateField; constructor() { this.#privateField = 42; this.#randomField = 666; # Syntax error } } const instance = new ClassWithPrivateField(); instance.#privateField === 42; // Syntax error
私有方法
静态私有方法
和静态公共方法一样,静态私有方法也是在类里面而非实例中调用的。和静态私有字段一样,它们也只能在类的声明中访问。
你可以使用生成器(generator)、异步和异步生成器方法。
静态私有方法可以是生成器、异步或者异步生成器函数。
class ClassWithPrivateStaticMethod { static #privateStaticMethod() { return 42; } static publicStaticMethod() { return ClassWithPrivateStaticMethod.#privateStaticMethod(); } } assert(ClassWithPrivateStaticField.publicStaticMethod() === 42);
私有实例方法
私有实例方法在类的实例中可用,它的访问方式的限制和私有实例字段相同。
class ClassWithPrivateMethod { #privateMethod() { return 'hello world'; } getPrivateMessage() { return #privateMethod(); } } const instance = new ClassWithPrivateMethod(); console.log(instance.getPrivateMessage()); // 预期输出值: "hello world"
私有实例方法可以是生成器、异步或者异步生成器函数。私有getter
和setter
也是可能的:
class ClassWithPrivateAccessor { #message; get #decoratedMessage() { return `✨${this.#message}✨`; } set #decoratedMessage(msg) { this.#message = msg; } constructor() { this.#decoratedMessage = 'hello world'; console.log(this.#decoratedMessage); } } new ClassWithPrivateAccessor(); // 预期输出值: "✨hello world✨"
浏览器兼容性
公共类字段
Desktop | Mobile | Server | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Public class fields | Chrome Full support 72 | Edge No support No | Firefox Full support 69 | IE No support No | Opera Full support 60 | Safari No support No | WebView Android Full support 72 | Chrome Android Full support 72 | Firefox Android No support No | Opera Android Full support 51 | Safari iOS No support No | Samsung Internet Android No support No | nodejs Full support 12.0.0 |
Legend
- Full support
- Full support
- No support
- No support
私有类字段
Desktop | Mobile | Server | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Private class fields | Chrome Full support 74 | Edge No support No | Firefox No support No | IE No support No | Opera Full support 62 | Safari No support No | WebView Android Full support 74 | Chrome Android Full support 74 | Firefox Android No support No | Opera Android Full support 53 | Safari iOS No support No | Samsung Internet Android No support No | nodejs Full support 12.0.0 |
Legend
- Full support
- Full support
- No support
- No support