Atualmente no ES5, muitos de nós estão usando o seguinte padrão em estruturas para criar classes e variáveis de classe, o que é confortável:
// ES 5
FrameWork.Class({
variable: 'string',
variable2: true,
init: function(){
},
addItem: function(){
}
});
No ES6, você pode criar classes nativamente, mas não há opção para ter variáveis de classe:
// ES6
class MyClass {
const MY_CONST = 'string'; // <-- this is not possible in ES6
constructor(){
this.MY_CONST;
}
}
Infelizmente, o acima não funcionará, pois apenas as classes podem conter métodos.
Eu entendo que eu posso this.myVar = true
em constructor
... mas eu não quero 'junk' meu construtor, especialmente quando tenho 20-30 + parâmetros para uma classe maior.
Eu estava pensando em várias maneiras de lidar com esse problema, mas ainda não encontrei nenhum bom. (Por exemplo: crie um ClassConfig
manipulador e passe um parameter
objeto que é declarado separadamente da classe. Em seguida, o manipulador seria anexado à classe. Eu estava pensando em WeakMaps
também integrar, de alguma forma.)
Que tipo de idéias você teria para lidar com essa situação?
fonte
this.member = member
no seu construtor com 20 a 30 parâmetros?public variable2 = true
em classe? Isso o definiria no protótipo.Respostas:
Atualização de 2018:
Agora existe uma proposta de estágio 3 - Estou ansioso para tornar essa resposta obsoleta em alguns meses.
Enquanto isso, qualquer pessoa que usa TypeScript ou babel pode usar a sintaxe:
Dentro de um corpo de declaração / expressão de classe, ele definirá uma variável. Espero que em alguns meses / semanas eu consiga postar uma atualização.
Atualização: o Chrome 74 agora é enviado com esta sintaxe funcionando.
As notas no wiki do ES para a proposta no ES6 ( classes mínimas mínimas ) observam:
Isso significa que o que você está pedindo foi considerado e explicitamente decidido contra.
mas por que?
Boa pergunta. As pessoas boas do TC39 desejam que as declarações de classe declarem e definam os recursos de uma classe. Não são seus membros. Uma declaração de classe ES6 define seu contrato para o usuário.
Lembre-se, uma definição de classe define métodos de protótipo - definir variáveis no protótipo geralmente não é algo que você faz. Você pode, é claro, usar:
No construtor como você sugeriu. Veja também o resumo do consenso .
ES7 e além
Uma nova proposta para o ES7 está sendo trabalhada, permitindo variáveis de instância mais concisas por meio de declarações e expressões de classe - https://esdiscuss.org/topic/es7-property-initializers
fonte
static
propriedadesstatic
funciona apenas para métodos também.Apenas para adicionar à resposta de Benjamin - variáveis de classe são possíveis, mas você não usaria
prototype
para defini-las.Para uma variável de classe verdadeira, você gostaria de fazer algo como o seguinte:
De dentro de um método de classe, essa variável pode ser acessada como
this.constructor.foo
(ouMyClass.foo
).Essas propriedades de classe geralmente não seriam acessíveis para a instância de classe. ou seja,
MyClass.foo
dá'bar'
masnew MyClass().foo
éundefined
Se você também quiser acessar sua variável de classe a partir de uma instância, precisará definir adicionalmente um getter:
Eu só testei isso com o Traceur, mas acredito que funcionará da mesma maneira em uma implementação padrão.
JavaScript realmente não tem classes . Mesmo com o ES6, estamos analisando uma linguagem baseada em objeto ou protótipo em vez de uma linguagem baseada em classe. Em qualquer
function X () {}
,X.prototype.constructor
aponta paraX
. Quando onew
operador é usadoX
, um novo objeto é criado herdandoX.prototype
. Quaisquer propriedades indefinidas nesse novo objeto (inclusiveconstructor
) são pesquisadas a partir daí. Podemos pensar nisso como gerar propriedades de objetos e classes.fonte
Babel suporta variáveis de classe no ESNext, verifique este exemplo :
fonte
No seu exemplo:
Devido ao MY_CONST ser primitivo, https://developer.mozilla.org/pt-BR/docs/Glossary/Primitive , podemos fazer:
Mas se
MY_CONST
é do tipo de referência, como astatic get MY_CONST() {return ['string'];}
saída de alerta é string, false . Nesse caso, odelete
operador pode fazer o truque:E finalmente para a variável de classe não
const
:fonte
delete
operador, se estiver sozinho por razões de desempenho. O que você realmente quer aqui éObject.defineProperty
.Como o seu problema é principalmente estilístico (não querendo encher o construtor com várias declarações), ele também pode ser resolvido estilisticamente.
Do meu ponto de vista, muitas linguagens baseadas em classes têm o construtor como uma função com o nome do próprio nome da classe. Estilisticamente, poderíamos usar isso para criar uma classe ES6 que estilisticamente ainda faz sentido, mas não agrupa as ações típicas que ocorrem no construtor com todas as declarações de propriedade que estamos fazendo. Simplesmente usamos o construtor JS real como a "área de declaração" e, em seguida, criamos uma classe denominada função que de outra forma tratamos como a área "outras coisas do construtor", chamando-a no final do construtor verdadeiro.
Ambos serão chamados quando a nova instância for construída.
É como ter dois construtores nos quais você separa as declarações e as outras ações que deseja executar, e estilisticamente torna difícil demais entender o que está acontecendo.
Acho que é um bom estilo de usar ao lidar com muitas declarações e / ou muitas ações que precisam acontecer na instanciação e que desejam manter as duas idéias distintas uma da outra.
OBSERVAÇÃO : propositalmente, não uso as idéias idiomáticas típicas de "inicializar" (como um
init()
ouinitialize()
método) porque essas são frequentemente usadas de maneira diferente. Existe uma espécie de diferença presumida entre a ideia de construir e inicializar. Ao trabalhar com construtores, as pessoas sabem que são chamadas automaticamente como parte da instanciação. Vendo uminit
método que muitas pessoas presumem, sem uma segunda olhada, que precisam fazer algo ao longo da formavar mc = MyClass(); mc.init();
, porque é assim que você normalmente inicializa. Não estou tentando adicionar um processo de inicialização para o usuário da classe, estou tentando adicionar ao processo de construção da própria classe.Embora algumas pessoas possam dar uma olhada duas vezes por um momento, esse é realmente o ponto: comunica a elas que a intenção faz parte da construção, mesmo que isso as faça dar uma olhada duas vezes e ir "não é como os construtores do ES6 funcionam "e dê uma segunda olhada no construtor real para dizer" ah, eles chamam isso de baixo, eu vejo ", isso é muito melhor do que NÃO comunicar essa intenção (ou comunicar incorretamente) e provavelmente obter muito pessoas usando errado, tentando inicializá-lo de fora e lixo. Isso é muito intencional para o padrão que sugiro.
Para aqueles que não querem seguir esse padrão, o oposto exato também pode funcionar. Farm as declarações para outra função no início. Talvez o nomeie "propriedades" ou "publicProperties" ou algo assim. Em seguida, coloque o restante do material no construtor normal.
Observe que esse segundo método pode parecer mais limpo, mas também tem um problema inerente, onde
properties
é substituído quando uma classe usando esse método se estende a outra. Você precisaria dar nomes mais exclusivosproperties
para evitar isso. Meu primeiro método não tem esse problema porque sua metade falsa do construtor é nomeada exclusivamente após a classe.fonte
init
.init
é um padrão usado com frequência e costuma ser chamado de fora da classe quando o usuário externo deseja inicializar, ou sejavar b = new Thing(); b.init();
. Essa é uma opção estilística 100% que eu preferiria comunicar que é uma segunda função que é automaticamente chamada, aproveitando os padrões encontrados em outros idiomas. É muito menos provável que alguém olhe para isso e suponha que precisa chamar oMyClass
método de fora, mais provavelmente perceberá que a intenção é um segundo método atuando na construção (isto é, chamado por si só na instanciação).MyClass
.$myvar
maneira padrão de se referir a variáveis destinadas a conter objetos jQuery não é convenientemente semelhante ao padrão de ter $ no início de variáveis às quais muitos programadores PHP estão acostumados. Apenas essa pequena implicação de que "sim, não é exatamente a mesma coisa ... mas veja ... ainda é uma variável, porque é assim que as variáveis são feitas em alguns idiomas!" ajuda.properties()
função No entanto, as coisas ficam um pouco mais complicadas ao estender as classes, portanto, sugiro que se você usar umaproperties()
função em todas as suas classes para declarar propriedades de classe, prefixe o nome do método com o nome da classe (IE:MyClassProperties()
para evitar substituição acidental) . chamadas de função dentro de subclasses Além disso, mantenha em mente que todas as chamadas parasuper()
deve ser declarado primeiro no construtor da classe.E o jeito da velha escola?
No construtor, você menciona apenas os vars que precisam ser computados. Gosto da herança de protótipo para esse recurso - ele pode ajudar a economizar muita memória (caso haja muitos vars nunca atribuídos).
fonte
Como Benjamin disse em sua resposta, o TC39 decidiu explicitamente não incluir esse recurso pelo menos no ES2015. No entanto, o consenso parece ser que eles serão adicionados no ES2016.
A sintaxe ainda não foi decidida, mas há uma proposta preliminar para o ES2016 que permitirá declarar propriedades estáticas em uma classe.
Graças à magia de babel, você pode usar isso hoje. Habilite a transformação das propriedades da classe de acordo com estas instruções e você estará pronto. Aqui está um exemplo da sintaxe:
Esta proposta está em um estágio muito inicial, portanto, esteja preparado para ajustar sua sintaxe com o passar do tempo.
fonte
[Tópico longo, não tenho certeza se ele já está listado como uma opção ...].
Uma alternativa simples apenas para os participantes seria definir a const fora da classe. Isso estará acessível apenas no próprio módulo, a menos que seja acompanhado por um getter.
Desta forma,
prototype
não está desarrumado e você recebe oconst
.fonte
var
vez deconst
2) usa várias instâncias dessa classe? Em seguida as variáveis externas será alterado com cada instância da classeES7
sintaxe do membro da classe:ES7
tem uma solução para 'juntar' sua função de construtor. Aqui está um exemplo:O exemplo acima ficaria com o seguinte em
ES6
:Ao usar isso, esteja ciente de que esta sintaxe pode não ser suportada por todos os navegadores e pode ter que ser transpilada para uma versão anterior do JS.
Bônus: uma fábrica de objetos:
fonte
Você pode imitar o comportamento das classes es6 ... e usar suas variáveis de classe :)
Coloquei no GitHub
fonte
A maneira como resolvi isso, que é outra opção (se você tiver o jQuery disponível), foi definir os campos em um objeto da velha escola e depois estender a classe com esse objeto. Eu também não queria encher o construtor de tarefas, essa parecia ser uma solução interessante.
- Atualização Após o comentário de Bergi.
Nenhuma versão JQuery:
Você ainda acaba com o construtor 'fat', mas pelo menos é tudo em uma classe e atribuído em um hit.
EDIÇÃO # 2: Eu já fiz um círculo completo e agora estou atribuindo valores no construtor, por exemplo
Por quê? Simples, usando os comentários acima, além de alguns comentários do JSdoc, o PHPStorm conseguiu executar o preenchimento de código nas propriedades. Atribuir todos os vars em uma ocorrência foi bom, mas a incapacidade de codificar concluir as propriedades, imo, não vale o benefício de desempenho (quase certamente minúsculo).
fonte
class
sintaxe, também é possívelObject.assign
. Não há necessidade de jQuery.MyClassFields
um construtor - ele não possui métodos. Você pode explicar por que você fez isso (em vez de, digamos, uma função simples de fábrica que retorna um objeto literal)?Bem, você pode declarar variáveis dentro do Construtor.
fonte
Ainda assim, você não pode declarar nenhuma classe como em outras linguagens de programação. Mas você pode criar tantas variáveis de classe. Mas o problema é o escopo do objeto de classe. Então, de acordo com mim, a melhor maneira de programação OOP no ES6 Javascript: -
fonte
Esta é uma combinação um pouco hackiana de estática e funciona para mim
usado em outro lugar
fonte
singleton_instance
como um nome de propriedade para que todos entendam o que você está fazendo aqui.