原文链接https://2ality.com/2019/07/public-class-fields.html
这篇博客是关于类定义中新成员的系列文章中的一部分:
这个系列取代了2ality’s prior blog post on fields
在这篇文章中,我们将探讨公有类字段,一般用来创建实例熟悉和静态属性。此功能是Daniel Ehrenberg和Jeff Morrison的ES提案“JavaScript的类字段声明”的一部分。
undefined
:class MyClass { counter; constructor() { } } assert.equal(new MyClass().counter, undefined);2.2. 公有静态字段 目前,在JavaScript中无法在类里面创建静态属性,你必须通过外部声明来创建它:class MyClass { } MyClass.prop = 123; assert.equal(MyClass.prop, 123);一个解决方法是创建静态的getter:
class MyClass {
static get prop() {
return 123;
}
}
assert.equal(MyClass.prop, 123);
而静态字段提供了更优雅的解决方案:
class MyClass {
static prop = 123;
}
assert.equal(MyClass.prop, 123);
相似的,与私有字段相比,“公有”描述了公共字段的性质。
.data
的创建移到构造函数外面,我们将不再需要构造函数:class StringBuilder { data = ''; add(str) { this.data += str; return this; } toString() { return this.data; } }5.高级 其余部分涵盖了公有字段的高级优点。 6. 通过构造函数创建属性和通过字段创建属性的一个重要区别是:前者使用赋值
,后者使用定义
。这两者分别意味着什么?6.1. 赋值属性
让我们首先来看看如何借助对象原型链来赋值
属性。这个操作赋值操作符触发(=)。在下面的例子里,我们为.prop
赋值(行A):
const proto = {
set prop(value) {
console.log('SETTER: '+value);
}
}
const obj = {
__proto__: proto
}
obj.prop = 123; // (A)
assert.equal(obj.prop, undefined);
// Output:
// 'SETTER: 123'
在类中,通过赋值创建一个属性还会调用一个setter(如果有的话)。在下面的例子里,我们同样为.prop
赋值(行A):
class A {
set prop(value) {
console.log('SETTER: '+value);
}
}
class B extends A {
constructor() {
super();
this.prop = 123; // (A)
}
}
assert.equal(new B().prop, undefined);
// Output:
// 'SETTER: 123'
6.2. 定义属性
我们再次用原型链的例子开始说明定义
一个属性是如何工作的。因为没有定义用的操作符,我们需要借助Object.defineProperty()来实现:
const proto = {
set prop(value) {
console.log('SETTER: '+value);
}
}
const obj = {
__proto__: proto
}
Object.defineProperty(obj, 'prop', {value: 123});
assert.equal(obj.prop, 123);
最后调用的.defineProperty()
是属性描述,可以为一个对象指定属性(字符串)。它的值是字符形式,同时包含其他特性如writable
——定义属性的值是否可变。
下面是一个使用定义而不是赋值创建的属性:
class A {
set prop(value) {
console.log('SETTER: '+value);
}
}
class B extends A {
prop = 123;
}
assert.equal(new B().prop, 123);
也就是说,公有字段总是创建属性并忽略setter。
6.3. 公有字段使用定义的利与弊
这是一些反对使用公有字段定义的争议点
这些是赞成使用定义的论据:
通常情况下,使用定义(而不是赋值)取决于对利弊的权衡。
super()
方法后被立即执行 看起来就像这样:在公有静态字段的初始化中,这指的是当前类:
class MyClass {
static prop = this;
}
assert.equal(MyClass.prop, MyClass);
此外,超类按预期工作:
class SuperClass {
getValue() {
return 123;
}
}
class SubClass extends SuperClass {
prop = super.getValue();
}
assert.equal(new SubClass().prop, 123);
更多关于属性的值、可写、可枚举、可配置的信息,参见"JavaScript for impatient programmers".
更多信息,参见对应提案