2015-02-11 5 views
47

Ich mache eine Javascript-Klasse und ich möchte ein öffentliches statisches Feld wie in Java haben. Dies ist der entsprechende Code:Wie mache ich ein "öffentliches statisches Feld" in einer ES6-Klasse?

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

Dies ist der Fehler, den ich bekommen:

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

Es sieht aus wie ES6 Module dies nicht zulassen. Gibt es eine Möglichkeit, das gewünschte Verhalten zu erreichen oder muss ich einen Getter schreiben?

+0

Welche ECMAScript 6-Motor Implementierung verwenden Sie? – Dai

+0

@Dai https://github.com/ModuleLoader/es6-module-loader – acbabis

Antwort

77

You "public static Feld" mit Accessor und einen "statischen" Schlüsslwort , 14.5 - Klassendefinitionen - Sie würden etwas verdächtig relevant sehen :)

ClassElement [Yield]: [? Yield] [? Yield]
    MethodDefinition
    statisch MethodDefinition;

So gibt von Ihnen 14.5.14 folgen können - Runtime Semantics: ClassDefinitionEvaluation - zu verdoppeln überprüfen, ob es wirklich tut, was es sieht aus wie es funktioniert. Genauer gesagt, Schritt 20:

  1. Für jeden ClassElement m in der Reihenfolge von Methoden
    1. Wenn IsStatic von m falsch, dann
      1. Let-Status für das Ergebnis seiner PropertyDefinitionEvaluation des Ausführens m mit Argumenten proto und false. Else
    2. ,
      1. Let Status das Ergebnis PropertyDefinitionEvaluation für m mit Argumenten F und falsch auszuführen.
    3. Wenn der Status eine abrupte Beendigung ist, dann
      1. Stellen Sie den Lauf LexicalEnvironment der Ausführungskontext lex.
      2. Rückgabestatus.

IsStatic früher in 14.5.9

definiert

ClassElement: static MethodDefinition
return true.

So PropertyMethodDefinition mit "F" (Konstruktor Funktionsobjekt) als ein Argument, das seinerseits creates an accessor method on that object genannt wird.

Diese in mindestens IETP (Tech-Vorschau), sowie 6to5 und Traceur Compiler.

+0

Für alle anderen Benutzer werden die statischen Accessor-Eigenschaften in Node noch nicht unterstützt. : -/ https://kangax.github.io/compat-table/es6/#class_computed_static_accessor_properties –

+1

Ab mindestens Node.js 6.x + wird dies unterstützt. – NuSkooler

+0

Beachten Sie, dass Sie, wenn Sie Flow benutzen, eine Zeile 'unsafe.enable_getters_and_setters = true' zu ​​Ihrer .flowconfig unter' [options] 'hinzufügen müssen (was ärgerlich ist). – kristina

22

In den aktuellen Entwürfen von ECMAScript 6 (Stand Februar 2015) müssen alle Klasseneigenschaften Methoden sein, keine Werte (beachten Sie in ECMAScript, dass eine "Eigenschaft" im Konzept einem OOP-Feld ähnelt, außer dass der Feldwert a sein muss Function Objekt, kein anderer Wert wie Number oder Object).

Sie immer noch diese mit traditionellen ECMAScript Konstruktoreigenschaft Bezeich angeben:

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

Agent.CIRCLE; // 1 

Mit Blick auf eine spec:

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

Beachten Sie, dass die ES6 'class' Syntax nur syntaktischer Zucker für traditionelle JS Konstruktorfunktionen und Prototypen ist. –

+0

Ich denke, Sie möchten diese Eigenschaften auf den Prototyp und nicht auf den Konstruktor setzen, damit sie über Eigenschaftenreferenzen von Instanzen sichtbar sind. – Pointy

+0

@Pointy Ich folgerte, dass das OP versucht, Konstanten als Referenz zu speichern (fast wie eine C# /. NET 'enum'). – Dai

2

Um die statische Variable voll auszunutzen, folgte ich diesem Ansatz. Um genauer zu sein, können wir es verwenden, um private Variable zu verwenden oder nur öffentliche Getter zu haben oder sowohl Getter als auch Setter zu haben. Im letzten Fall ist es dasselbe wie eine der oben genannten Lösungen.

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']; 

Ich könnte eine andere Klasse erstellen erweitern Url und es hat funktioniert.

Ich benutzte babel mein ES6 Code zu konvertieren

+1

Was ist "voller Vorteil"? Wäre nicht 'class Url {static getQueries ...}; Url.staticMember = []; 'waren viel einfacher? – Bergi

+0

Diese '===' Vergleiche ergeben beide 'false', btw – Bergi

+0

" Full Advantage "bedeutet, dass Sie _staticMember wie oben beschrieben privat halten können, wenn Sie möchten. –

26

bis ES5 Es gibt eine Stufe 3 ECMAScript Vorschlag "Class Fields" von Daniel Ehrenberg und Jeff Morrison genannt, die dieses Problem lösen soll.

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' 
    } 
} 

Die oben entspricht:

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 Klassenfelder durch @babel/plugin-proposal-class-properties (im stage-3 preset enthalten), so dass Sie diese Funktion auch Laufzeit nicht unterstützt, wenn Ihr JavaScript verwenden können es.


Im Vergleich zu @ kangax-Lösung einen Getter zu erklären, kann diese Lösung auch performanter sein, da hier die Eigenschaft direkt von durch den Aufruf einer Funktion statt zugegriffen wird.

Wenn dieser Vorschlag akzeptiert wird, dann wird es möglich sein, JavaScript-Code in einer Weise zu schreiben, die traditionellen objektorientierten Sprachen wie Java und C♯ ähnlicher ist.


bearbeitet: Ein einheitliches Klassenfelder Vorschlag ist jetzt in der Stufe 3; Update auf Babel v7.x-Pakete.

1

@kangax ‚s Antwort nicht die gesamte statische Verhalten der traditionellen OOP Sprache imitieren, weil Sie nicht die statische Eigenschaft zugreifen, indem sie beispielsweise ist wie const agent = new Agent; agent.CIRCLE; // Undefined

Wenn Sie wie OOP statische Eigenschaft zugreifen möchten, ist hier meine Lösung:

class NewApp { 
    get MULTIPLE_VERSIONS_SUPPORTED() { 
    return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; // Late binding for inheritance 
    } 
} 

NewApp.MULTIPLE_VERSIONS_SUPPORTED = true; 

Prüfregeln wie folgt.

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

Verwandte Themen