我正在制作一个Javascript课程,我希望有一个像Java一样的公共静态字段。这是相关的代码:
export default class Agent {
CIRCLE: 1,
SQUARE: 2,
...
这是我得到的错误:
line 2, col 11, Class properties must be methods. Expected '(' but instead saw ':'.
看起来ES6模块不允许这样做。有没有办法获得理想的行为,还是我必须写一个吸气剂?
答案 0 :(得分:115)
使用访问者和“静态”关键字制作“公共静态字段”:
class Agent {
static get CIRCLE() {
return 1;
}
static get SQUARE() {
return 2;
}
}
Agent.CIRCLE; // 1
查看规范,14.5 - 类定义 - 您会看到一些可疑的相关内容:)
ClassElement [Yield]:
MethodDefinition [?收率]
静态 MethodDefinition [?Yield];
从那里你可以按照14.5.14 - 运行时语义:ClassDefinitionEvaluation - 来仔细检查它是否真的像它看起来那样。具体来说,步骤20:
- 对于每个ClassElement m,按顺序排序
醇>
- 如果 m的IsStatic为假,那么
- 让状态为使用参数proto和false对m执行PropertyDefinitionEvaluation的结果。
- 否则,
- 让状态为使用参数F和false对m执行PropertyDefinitionEvaluation的结果。
- 如果状态突然完成,那么
- 将正在运行的执行上下文的LexicalEnvironment设置为lex。
- 退货状态。
先前在14.5.9
中定义了IsStaticClassElement:static MethodDefinition
返回true。
因此PropertyMethodDefinition
以“F”(构造函数,函数对象)作为参数调用,而creates an accessor method on that object依次调用{{1}}。
此already works至少在IETP(技术预览版)中,以及6to5和Traceur编译器。
答案 1 :(得分:41)
Daniel Ehrenberg和Jeff Morrison提出了一个名为"Class Fields"的第3阶段ECMAScript提案,旨在解决这个问题。
class MyClass {
static myStaticProp = 42;
myProp = 42;
myProp2 = this.myProp;
myBoundFunc = () => { console.log(this.myProp); };
constructor() {
console.log(MyClass.myStaticProp); // Prints '42'
console.log(this.myProp); // Prints '42'
this.myBoundFunc(); // Prints '42'
}
}
以上相当于:
class MyClass {
constructor() {
this.myProp = 42;
this.myProp2 = this.myProp;
this.myBoundFunc = () => { console.log(this.myProp); };
console.log(MyClass.myStaticProp); // Prints '42'
console.log(this.myProp); // Prints '42'
this.myBoundFunc(); // Prints '42'
}
}
MyClass.myStaticProp = 42;
Babel supports通过@babel/plugin-proposal-class-properties(包含在stage-3 preset中)转换类字段,以便即使您的JavaScript运行时没有使用此功能也可以使用此功能支持它。
与@ kangax的声明getter的解决方案相比,这个解决方案也可以更高效,因为这里直接访问属性而不是通过调用函数。
如果该提议被接受,那么就可以以类似于传统的面向对象语言(如Java和C♯)的方式编写JavaScript代码。
编辑:统一的班级字段提案现在处于第3阶段;更新到Babel v7.x软件包。
答案 2 :(得分:27)
在ECMAScript 6的当前草案中(截至2015年2月),所有类属性必须是方法,而不是值(ECMAScript中注释a"属性"在概念上类似于OOP字段,除了字段值必须是Function
对象,而不是Number
或Object
等任何其他值。
您仍然可以使用传统的ECMAScript构造函数属性说明符指定它们:
class Agent {
}
Agent.CIRCLE = 1;
Agent.SQUARE = 2;
...
答案 3 :(得分:4)
为了充分利用静态变量,我采用了这种方法。更具体地说,我们可以使用它来使用私有变量或只使用公共getter,或同时使用getter或setter。在最后一种情况下,它与上面公布的解决方案相同。
var Url = (() => {
let _staticMember = [];
return class {
static getQueries(hash = document.location.hash) {
return hash;
}
static get staticMember(){
return _staticMember;
}
};
})();
Usages:
console.log(Url.staticMember); // [];
Url.staticMember.push('it works');
console.log(Url.staticMember); // ['it works'];
我可以创建另一个扩展Url的类,但它有效。
我使用babel将我的ES6代码转换为ES5
答案 4 :(得分:1)
@kangax的答案并不模仿传统OOP语言的整个静态行为,因为你不能通过它的实例来访问静态属性,如const agent = new Agent; agent.CIRCLE; // Undefined
如果你想像OOP一样访问静态属性,这是我的解决方案:
class NewApp {
get MULTIPLE_VERSIONS_SUPPORTED() {
return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; // Late binding for inheritance
}
}
NewApp.MULTIPLE_VERSIONS_SUPPORTED = true;
测试代码如下。
class NewApp {
get MULTIPLE_VERSIONS_SUPPORTED() {
console.log('this.constructor.name:', this.constructor.name); // late binding
return this.constructor.MULTIPLE_VERSIONS_SUPPORTED;
}
}
// Static property can be accessed by class
NewApp.MULTIPLE_VERSIONS_SUPPORTED = true;
const newApp = new NewApp;
// Static property can be accessed by it's instances
console.log('newApp.MULTIPLE_VERSIONS_SUPPORTED:', newApp.MULTIPLE_VERSIONS_SUPPORTED); // true
// Inheritance
class StandardApp extends NewApp {}
// Static property can be inherited
console.log('StandardApp.MULTIPLE_VERSIONS_SUPPORTED:', StandardApp.MULTIPLE_VERSIONS_SUPPORTED); // true
// Static property can be overwritten
StandardApp.MULTIPLE_VERSIONS_SUPPORTED = false;
const std = new StandardApp;
console.log('std.MULTIPLE_VERSIONS_SUPPORTED:', std.MULTIPLE_VERSIONS_SUPPORTED); // false