属性只有declared个一次(在构造函数之外);如果没有这些声明,就不会有这些属性的声明(而是通过赋值创建).公共属性声明(也称为"公共类字段")是可选的,但可以帮助避免对象中的形状更改(这可以提高效率)和/或减少JavaScript引擎为避免形状更改而需要对创建的对象进行的分析.基本上,它们提供了一种declarative(而不是命令式[逐步])的方式来表示(在本例中)Rectangle
个对象始终具有height
和width
属性.虽然JavaScript引擎可以通过分析构造函数代码来解决这个问题,但声明意味着它不必担心(对于那些属性).
构造函数之外的高度和宽度不是没有意义吗,因为它们总是在构造函数中被覆盖?
height
属性上的初始值设定项(= 0
)毫无意义,是的,因为它会被构造函数中的代码明确地覆盖,这样做的赋值是构造函数中的第一条语句.如果它不是第一条语句,那么构造函数中的代码将能够在赋值之前观察height
中的0
.
[the height and width declaration/initialization outside of constructor]是否已使用/可通过任何方式访问?
它们可以由后续的类字段初始值设定项使用.例如,这是有效的:
class Example {
a = 2;
b = this.a * 3;
}
console.log(new Example().b); // 6
可能还值得指出的是,如果类是一个子类,则有一点不同:当您使用声明语法时,属性是通过"define"语义创建的(就像您使用Object.defineProperty
函数一样),而如果您只对其赋值,则使用赋值语义.如果超类还定义了属性,那么这很重要:
class Super {
#example = 42;
get example() {
console.log("Getting example");
return this.#example;
}
set example(value) {
console.log("Setting example");
this.#example = value;
}
}
class Sub extends Super {
example = 67;
}
const super1 = new Super();
console.log(`What kind of property is super1.example?`);
console.log(propertyKind(super1, "example"));
const sub1 = new Sub();
console.log(`What kind of property is sub1.example?`);
console.log(propertyKind(sub1, "example"));
function propertyKind(obj, name) {
let descr;
do {
descr = Object.getOwnPropertyDescriptor(obj, name);
if (descr) {
break;
}
obj = Object.getPrototypeOf(obj);
if (!obj) {
break;
}
} while (!descr);
return descr
? "value" in descr
? "data"
: "accessor" // presumably
: "none";
}
请注意,example
是super1
上的访问器属性(通过从其原型继承),但它是sub1
上的data
属性,因为它是redeclared乘Sub
.如果Sub
刚刚分配给它,它将只使用创建的属性Super
:
class Super {
#example = 42;
get example() {
console.log("Getting example");
return this.#example;
}
set example(value) {
console.log("Setting example");
this.#example = value;
}
}
class Sub extends Super {
constructor() {
super();
this.example = 67;
}
}
const super1 = new Super();
console.log(`What kind of property is super1.example?`);
console.log(propertyKind(super1, "example"));
const sub1 = new Sub();
console.log(`What kind of property is sub1.example?`);
console.log(propertyKind(sub1, "example"));
function propertyKind(obj, name) {
let descr;
do {
descr = Object.getOwnPropertyDescriptor(obj, name);
if (descr) {
break;
}
obj = Object.getPrototypeOf(obj);
if (!obj) {
break;
}
} while (!descr);
return descr
? "value" in descr
? "data"
: "accessor" // presumably
: "none";
}
请注意,现在,它是sub1
和super1
上的访问器属性(当Sub
进行赋值时,Super.example
中的setter代码运行).
TL;DR-我会保留声明以保持清晰和潜在的效率,但删除height
上的= 0
初始值设定项,因为该值显然永远不会被使用.