2015-02-11 400 views
47

我正在做一个Javascript类,我想有一个像Java一样的公共静态字段。这是相关代码:如何在ES6课程中创建“公共静态字段”?

export default class Agent { 
    CIRCLE: 1, 
    SQUARE: 2, 
    ... 

这是我的错误:

line 2, col 11, Class properties must be methods. Expected '(' but instead saw ':'. 

它看起来像ES6模块不允许这样。有没有办法获得想要的行为,还是必须写一个getter?

+0

其中的ECMAScript 6引擎实现您使用? – Dai 2015-02-11 02:54:34

+0

@Dai https://github.com/ModuleLoader/es6-module-loader – acbabis 2015-02-11 03:07:14

回答

77

你让“公共静态字段”使用访问和一个“静态”的文章:

class Agent { 
    static get CIRCLE() { 
     return 1; 
    } 
    static get SQUARE() { 
     return 2; 
    } 
} 

Agent.CIRCLE; // 1 

看着一个规范,14.5 - 类定义 - 你会看到一些可疑相关的东西:)

ClassElement [产率]:[?收率] [?收率]
    MethodDefinition
    静态 MethodDefinition;

因此,从那里你可以按照14.5.14 - 运行时语义:ClassDefinitionEvaluation - 仔细检查它是否确实做它看起来像它。具体而言,步骤20:

  1. 对于每个ClassElement米为了从方法
    1. 如果m IsStatic是假,然后
      1. 令状态是用于执行PropertyDefinitionEvaluation的结果与原始和虚假的论点。
    2. 否则,
      1. 让状态为带参数F和假米进行PropertyDefinitionEvaluation的结果。
    3. 如果状态是突然完成,然后
      1. 将运行中的执行上下文的LexicalEnvironment莱克斯。
      2. 返回状态。静态MethodDefinition
        返回true:

IsStatic在14.5.9

ClassElement前面定义。

所以PropertyMethodDefinition被称为“F”(构造函数,函数对象)作为参数,它依次为creates an accessor method on that object

already works在至少IETP(技术预览),以及6to5和Traceur编译器。

+0

对于其他人来说,Node中不支持静态访问器属性。 : -/ https://kangax.github.io/compat-table/es6/#class_computed_static_accessor_properties – 2015-06-06 19:05:10

+1

至少支持Node.js 6.x +。 – NuSkooler 2017-02-18 19:46:22

+0

请注意,如果您使用的是流程,则必须在'[options]'下的.flowconfig中添加一行'unsafe.enable_getters_and_setters = true'(这很烦人)。 – kristina 2018-03-01 15:29:49

22

在当前的ECMAScript 6草案中(截至2015年2月),所有类属性都必须是方法,而不是值(ECMAScript中的注释“属性”与OOP字段的概念相似,除了字段值必须是Function对象,而不是任何其他值,例如NumberObject)。

您仍然可以指定这些用传统的ECMAScript constructor属性符:

class Agent { 
} 
Agent.CIRCLE = 1; 
Agent.SQUARE = 2; 
... 
+9

请注意,ES6'class'语法只是传统JS构造函数和原型的语法糖。 – 2015-02-11 02:54:43

+0

我想你会想把这些属性放在原型上,而不是在构造函数上,以便通过实例的属性引用来显示它们。 – Pointy 2015-02-11 03:02:27

+0

@Pointy我推断OP正在尝试存储常量以供参考(几乎像C#/ .NET的'enum')。 – Dai 2015-02-11 03:04:35

2

为了充分利用静态变量我遵循这种方法。更具体地说,我们可以使用它来使用私有变量或者只有公有的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的类,它工作。

我用巴贝尔转换器ES6我的代码ES5

+1

什么是“充分优势”?不会'class Url {static getQueries ...}; Url.staticMember = [];'已经简单得多了? – Bergi 2015-07-06 00:14:05

+0

这些'==='比较都产生'false',顺便说一句 – Bergi 2015-07-06 00:14:27

+0

“完整优势”的意思是,以上述方式可以将_staticMember保留为私人的,如果你想。 – 2015-07-06 00:44:55

26

有一个叫"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; 

Babelsupports transpiling类字段通过@babel/plugin-proposal-class-properties(包含在stage-3 preset),这样就可以使用此功能,即使你的JavaScript运行时不支持它。


相比@ kangax的声明吸气的解决方案,该解决方案还可以更好的性能,因为这里的属性是通过调用函数访问,而不是直接的。

如果这个建议被接受,那么有可能以一种更类似于传统的面向对象的语言如Java和C♯的方式编写JavaScript代码。


编辑:现在统一类领域的建议是在第3阶段;更新到Babel v7.x软件包。

1

@kangax的回答不模仿传统的面向对象编程语言的整个静态行为,因为它的实例像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

相关问题