Estou fazendo uma classe Javascript e gostaria de ter um campo estático público como em Java. Este é o código relevante:
export default class Agent {
CIRCLE: 1,
SQUARE: 2,
...
Este é o erro que recebo:
line 2, col 11, Class properties must be methods. Expected '(' but instead saw ':'.
Parece que os módulos ES6 não permitem isso. Existe uma maneira de obter o comportamento desejado ou tenho que escrever um getter?
javascript
ecmascript-6
class-fields
aebabis
fonte
fonte
Respostas:
Você torna "campo estático público" usando o acessador e uma palavra-chave "estática":
class Agent { static get CIRCLE() { return 1; } static get SQUARE() { return 2; } } Agent.CIRCLE; // 1
Olhando para uma especificação, 14.5 - Definições de classe - você veria algo suspeitamente relevante :)
Então, de lá você pode seguir para 14.5.14 - Runtime Semantics: ClassDefinitionEvaluation - para verificar se ele realmente faz o que parece que faz. Especificamente, etapa 20:
IsStatic é definido anteriormente em 14.5.9
Portanto,
PropertyMethodDefinition
é chamado com "F" (construtor, objeto de função) como um argumento, que por sua vez cria um método acessador nesse objeto .Isso já funciona pelo menos em IETP (visualização técnica), bem como compiladores 6to5 e Traceur.
fonte
unsafe.enable_getters_and_setters=true
ao seu .flowconfig em[options]
(o que é irritante).Existe uma proposta ECMAScript de Estágio 3 chamada "Static Class Features" por Daniel Ehrenberg e Jeff Morrison que visa resolver este problema. Junto com a proposta de "Campos de classe" do Estágio 3 , o código futuro será semelhante a este:
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' } }
O acima é 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;
O Babel oferece suporte à transpilação de campos de classe por meio de @ babel / plugin-proposal-class-properties (incluído na predefinição do estágio 3 ), para que você possa usar esse recurso mesmo se o tempo de execução do JavaScript não o suportar.
Em comparação com a solução de @kangax de declarar um getter, essa solução também pode ter mais desempenho, já que aqui a propriedade é acessada diretamente em vez de chamar uma função.
Se essa proposta for aceita, será possível escrever o código JavaScript de uma forma mais semelhante às linguagens orientadas a objetos tradicionais, como Java e C♯.
Editar : Uma proposta de campos de classe unificados está agora no estágio 3; atualização para pacotes Babel v7.x.
Editar (fevereiro de 2020) : Os recursos de classe estática foram divididos em uma proposta diferente. Obrigado @ GOTO0!
fonte
Nos rascunhos atuais do ECMAScript 6 (em fevereiro de 2015), todas as propriedades da classe devem ser métodos, não valores (observe no ECMAScript uma "propriedade" é semelhante em conceito a um campo OOP, exceto que o valor do campo deve ser um
Function
objeto, não qualquer outro valor, como aNumber
ouObject
).Você ainda pode especificá-los usando os especificadores de propriedade do construtor ECMAScript tradicionais:
class Agent { } Agent.CIRCLE = 1; Agent.SQUARE = 2; ...
fonte
class
sintaxe ES6 é apenas um açúcar sintático para funções e protótipos tradicionais do construtor JS.enum
).class
sintaxe também tem algumas diferenças de nuances. Por exemplo, um método declarado comClass.prototype.method = function () {};
é enumerável (visível com loops for-in), enquanto osclass
métodos não são enumeráveis.Para obter todas as vantagens da variável estática, segui essa abordagem. Para ser mais específico, podemos usá-lo para usar a variável privada ou ter apenas getter público, ou ter ambos getter ou setter. No último caso, é igual a uma das soluções postadas acima.
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'];
Eu poderia criar outra classe estendendo Url e funcionou.
Usei o babel para converter meu código ES6 para ES5
fonte
class Url { static getQueries… }; Url.staticMember = [];
teria sido muito mais simples?===
comparações tanto rendimentofalse
, aliásA resposta de @kangax não imita todo o comportamento estático da linguagem OOP tradicional, porque você não pode acessar a propriedade estática por sua instância como
const agent = new Agent; agent.CIRCLE; // Undefined
Se você deseja acessar a propriedade estática como a OOP, aqui está minha solução:
class NewApp { get MULTIPLE_VERSIONS_SUPPORTED() { return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; // Late binding for inheritance } } NewApp.MULTIPLE_VERSIONS_SUPPORTED = true;
Teste o código da seguinte maneira.
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
fonte
static
campo por uma instância seria bastante incomum, não é? Em algumas linguagens, como Java, o IDE realmente emite um aviso / dica se você fizer algo assim.