2015-02-11 50 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