Come faccio a creare un “campo statico pubblico” in una class ES6?

Sto facendo una lezione di Javascript e mi piacerebbe avere un campo statico pubblico come in Java. Questo è il codice rilevante:

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

Questo è l’errore che ottengo:

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

Sembra che i moduli ES6 non lo consentano. C’è un modo per ottenere il comportamento desiderato o devo scrivere un getter?

Rendi “campo statico pubblico” usando accessor e una parola chiave “statica”:

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

Guardando una specifica, 14.5 – Definizioni di class – vedresti qualcosa di sospetto rilevante 🙂

ClassElement [Rendimento]:
MethodDefinition [? Resa]
MethodDefinition statico [? Resa];

Quindi da lì puoi seguire 14.5.14 – Runtime Semantics: ClassDefinitionEvaluation – per ricontrollare se fa veramente quello che sembra. Nello specifico, passaggio 20:

  1. Per ogni ClassElement m in ordine dai metodi
    1. Se IsStatic di m è falso , allora
      1. Lascia che lo stato sia il risultato dell’esecuzione di PropertyDefinitionEvaluation per m con argomenti proto e false.
    2. Altro,
      1. Lascia che lo stato sia il risultato dell’esecuzione di PropertyDefinitionEvaluation per m con gli argomenti F e false.
    3. Se lo stato è un completamento brusco, allora
      1. Impostare LexicalEnvironment del contesto di esecuzione in esecuzione su lex.
      2. Stato di ritorno

IsStatic è definito in precedenza in 14.5.9

ClassElement: MethodDefinition statico
Restituire vero.

Quindi PropertyMethodDefinition viene chiamato con “F” (costruttore, object funzione) come argomento, che a sua volta crea un metodo accessor su quell’object .

Funziona già almeno in IETP (anteprima tecnica), oltre ai compilatori 6to5 e Traceur.

C’è una proposta ECMAScript Stage 3 chiamata “Class Fields” di Daniel Ehrenberg e Jeff Morrison che ha lo scopo di risolvere questo problema.

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

Quanto sopra è equivalente a:

 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 supporta il transpiling dei campi di class tramite le proprietà di class @ babel / plug-in-proposal (incluse nel preset stage-3 ), in modo da poter utilizzare questa funzione anche se il runtime JavaScript non lo supporta.


Rispetto alla soluzione di @ kangax di dichiarare un getter, questa soluzione può anche essere più performante, poiché qui si accede direttamente alla proprietà invece di chiamare una funzione.

Se questa proposta viene accettata, sarà ansible scrivere codice JavaScript in un modo più simile ai tradizionali linguaggi orientati agli oggetti come Java e C♯.


Modifica : una proposta di campi di class unificata è ora nella fase 3; aggiornamento ai pacchetti Babel v7.x.

Nelle bozze correnti di ECMAScript 6 (a febbraio 2015), tutte le proprietà di class devono essere metodi, non valori (nota in ECMAScript una “proprietà” è simile nel concetto a un campo OOP, tranne che il valore del campo deve essere un object Function , non qualsiasi altro valore come un Number o un Object ).

È ancora ansible specificare questi utilizzando gli specificatori di proprietà del costruttore ECMAScript tradizionali:

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

Per trarre il massimo vantaggio dalla variabile statica ho seguito questo approccio. Per essere più specifici, possiamo usarlo per usare variabili private o avere solo getter pubblici, o avere entrambi getter o setter. Nell’ultimo caso è uguale a una delle soluzioni pubblicate sopra.

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

Potrei creare un’altra class estendendo Url e ha funzionato.

Ho usato babel per convertire il mio codice ES6 in ES5

La risposta di @kangax non imita l’intero comportamento statico dei linguaggi OOP tradizionali, perché non è ansible accedere alla proprietà statica tramite la sua istanza come const agent = new Agent; agent.CIRCLE; // Undefined const agent = new Agent; agent.CIRCLE; // Undefined

Se vuoi accedere alla proprietà statica proprio come quella di OOP, ecco la mia soluzione:

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

Testare il codice come segue.

 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