É possível criar propriedades particulares nas classes ES6?
Aqui está um exemplo. Como posso impedir o acesso instance.property
?
class Something {
constructor(){
this.property = "test";
}
}
var instance = new Something();
console.log(instance.property); //=> "test"
Respostas:
Campos privados (e métodos) estão sendo implementados no padrão ECMA . Você pode começar a usá-los hoje com as predefinições babel 7 e estágio 3.
fonte
this
no construtor antes de ligarsuper()
. No entanto, babel os coloca antes de super.#privateCrap
sintaxe?#beep() {}
:; e issoasync #bzzzt() {}
:?Resposta curta, não, não há suporte nativo para propriedades particulares com classes ES6.
Mas você pode imitar esse comportamento não anexando as novas propriedades ao objeto, mas mantendo-as dentro de um construtor de classe e usar getters e setters para alcançar as propriedades ocultas. Observe que os getters e setters são redefinidos a cada nova instância da classe.
ES6
ES5
fonte
class
sintaxe em primeiro lugar.getName
esetName
privadas?Para expandir a resposta de @ loganfsmyth:
Os únicos dados verdadeiramente privados em JavaScript ainda são variáveis de escopo. Você não pode ter propriedades privadas no sentido de propriedades acessadas internamente da mesma maneira que propriedades públicas, mas pode usar variáveis de escopo para armazenar dados privados.
Variáveis de escopo
A abordagem aqui é usar o escopo da função construtora, que é privada, para armazenar dados privados. Para que os métodos tenham acesso a esses dados privados, eles também devem ser criados no construtor, o que significa que você os está recriando a cada instância. Essa é uma penalidade de desempenho e memória, mas alguns acreditam que a penalidade é aceitável. A penalidade pode ser evitada para métodos que não precisam de acesso a dados privados, adicionando-os ao protótipo como de costume.
Exemplo:
Escopo FracoMapa
Um WeakMap pode ser usado para evitar o desempenho da abordagem anterior e a penalidade de memória. O WeakMaps associa os dados aos Objetos (aqui, instâncias) de forma que eles só possam ser acessados usando esse WeakMap. Portanto, usamos o método de variáveis com escopo definido para criar um WeakMap privado e, em seguida, usamos esse WeakMap para recuperar dados privados associados a
this
. Isso é mais rápido que o método das variáveis com escopo definido, porque todas as suas instâncias podem compartilhar um único WeakMap; portanto, você não precisa recriar métodos apenas para fazê-los acessar seus próprios WeakMaps.Exemplo:
Este exemplo usa um Objeto para usar um WeakMap para várias propriedades particulares; você também pode usar vários WeakMaps e usá-los como
age.set(this, 20)
, ou escrever um pequeno invólucro e usá-lo de outra maneira, comoprivateProps.set(this, 'age', 0)
.Teoricamente, a privacidade dessa abordagem pode ser violada ao se adulterar o
WeakMap
objeto . Dito isto, todo o JavaScript pode ser quebrado por globals mutilados. Nosso código já foi desenvolvido com base no pressuposto de que isso não está acontecendo.(Esse método também pode ser feito
Map
, masWeakMap
é melhor, porqueMap
criará vazamentos de memória, a menos que você tenha muito cuidado e, para esse fim, os dois não são diferentes.)Meia resposta: símbolos com escopo
Um símbolo é um tipo de valor primitivo que pode servir como um nome de propriedade. Você pode usar o método de variável com escopo definido para criar um símbolo particular e armazenar dados particulares em
this[mySymbol]
.A privacidade desse método pode ser violada usando
Object.getOwnPropertySymbols
, mas é um pouco difícil de fazer.Exemplo:
Meia resposta: sublinhados
O padrão antigo, basta usar uma propriedade pública com um prefixo de sublinhado. Embora não seja uma propriedade privada de forma alguma, essa convenção é predominante o suficiente para que ele faça um bom trabalho comunicando que os leitores devem tratar a propriedade como privada, o que geralmente faz o trabalho. Em troca desse lapso, obtemos uma abordagem mais fácil de ler, mais fácil de digitar e mais rápida.
Exemplo:
Conclusão
No ES2017, ainda não havia uma maneira perfeita de fazer propriedades particulares. Várias abordagens têm prós e contras. Variáveis com escopo definido são verdadeiramente privadas; WeakMaps com escopo definido é muito particular e mais prático do que variáveis com escopo definido; Símbolos com escopo definido são razoavelmente particulares e razoavelmente práticos; sublinhados costumam ser privados o suficiente e muito práticos.
fonte
instanceof
. Admito que estava pensando nessa abordagem como incluída apenas por uma questão de exaustividade e deveria ter pensado mais em quanto ela é realmente capaz.Atualização: uma proposta com sintaxe mais agradável está a caminho. Contribuições são bem-vindas.
Sim, existe - para acesso com escopo definido em objetos - o ES6 apresenta
Symbol
s .Os símbolos são únicos, você não pode obter acesso a um externo, exceto com reflexão (como privates em Java / C #), mas qualquer pessoa que tenha acesso a um símbolo interno pode usá-lo para acesso à chave:
fonte
Object.getOwnPropertySymbols
? ;)const myPrivateMethod = Math.random(); Something.prototype[''+myPrivateMethod] = function () { ... } new Something()[''+myPrivateMethod]();
. Isso não é realmente privacidade, é obscuridade, no sentido do JavaScript tradicional. Eu consideraria JavaScript "privado" como o uso de fechamentos para encapsular variáveis. Portanto, essas variáveis não são acessíveis através da reflexão.private
-protected
chave e seria muito mais limpo queSymbol
ouName
. Eu prefiro a notação de ponto em vez da colchete. Eu gostaria de continuar usando um ponto para coisas particulares.this.privateVar
A resposta é não". Mas você pode criar acesso privado a propriedades como esta:
export
palavra chave.(A sugestão de que o Symbols pudesse ser usado para garantir a privacidade era verdadeira em uma versão anterior da especificação ES6, mas não é mais o caso: https://mail.mozilla.org/pipermail/es-discuss/2014-January/035604. html e https://stackoverflow.com/a/22280202/1282216 . Para uma discussão mais longa sobre símbolos e privacidade, consulte: https://curiosity-driven.org/private-properties-in-javascript )
fonte
A única maneira de obter verdadeira privacidade no JS é através do escopo, portanto, não há como ter uma propriedade que seja membro,
this
que estará acessível apenas dentro do componente. A melhor maneira de armazenar dados verdadeiramente privados no ES6 é com um WeakMap.Obviamente, isso é provavelmente lento, e definitivamente feio, mas fornece privacidade.
Lembre-se de que MESMO ISSO não é perfeito, porque o Javascript é muito dinâmico. Alguém ainda poderia fazer
para capturar valores à medida que são armazenados, por isso, se você quiser ter cuidado extra, precisará capturar uma referência local
.set
e.get
usar explicitamente em vez de confiar no protótipo substituível.fonte
get
para um por método (por exemploconst _ = privates.get(this); console.log(_.privateProp1);
).const myObj = new SomeClass(); console.log(privateProp1.get(myObj)) // "I am Private1"
isso significa que sua propriedade é privada ou não?Para referência futura de outros usuários, estou ouvindo agora que a recomendação é usar o WeakMaps para armazenar dados particulares.
Aqui está um exemplo de trabalho mais claro:
fonte
Depende de quem você pergunta :-)
Nenhum
private
modificador de propriedade está incluído na proposta Maximally minimal classes , que parece ter entrado no rascunho atual .No entanto, pode haver suporte para nomes particulares , o que permite propriedades particulares - e elas provavelmente também podem ser usadas nas definições de classe.
fonte
O uso de módulos ES6 (inicialmente proposto por @ d13) funciona bem para mim. Ele não imita propriedades privadas perfeitamente, mas pelo menos você pode ter certeza de que propriedades que deveriam ser privadas não vazarão para fora da sua classe. Aqui está um exemplo:
something.js
Em seguida, o código de consumo pode ficar assim:
Atualização (importante):
Como @DanyalAytekin descrito nos comentários, essas propriedades privadas são estáticas, portanto, de escopo global. Eles funcionarão bem ao trabalhar com Singletons, mas é preciso ter cuidado com objetos transitórios. Estendendo o exemplo acima:
fonte
private static
.a.say(); // a
deve serb.say(); // b
let _message = null
, não tão legal, quando o construtor de chamadas várias vezes, ele estraga tudo.Concluindo @ d13 e os comentários de @ johnny-oshika e @DanyalAytekin:
Eu acho que no exemplo fornecido por @ johnny-oshika, poderíamos usar funções normais em vez de funções de seta e depois
.bind
com o objeto atual mais um_privates
objeto como um parâmetro ao curry:something.js
main.js
Benefícios em que posso pensar:
_greet
e_updateMessage
agir como métodos privados, desde que nãoexport
as referências)_privates
objeto vinculadoAlgumas desvantagens que posso pensar:
Um snippet em execução pode ser encontrado aqui: http://www.webpackbin.com/NJgI5J8lZ
fonte
Sim - você pode criar uma propriedade encapsulada , mas isso não foi feito com modificadores de acesso (público | privado) pelo menos não com o ES6.
Aqui está um exemplo simples de como isso pode ser feito com o ES6:
1 Crie uma classe usando a palavra da classe
2 Dentro do construtor declarar bloco escopo variável usando let OU const palavras reservadas -> uma vez que são bloco-scope eles não podem ser acessados de fora (encapsulados)
3 Para permitir algum controle de acesso (setters | getters) a essas variáveis, você pode declarar o método da instância dentro do construtor usando:
this.methodName=function(){}
sintaxeAgora vamos verificar:
fonte
new Something();
porque seus métodos são declarados no construtor para ter acesso a estes. variáveis privadas. Isso pode causar muito consumo de memória se você criar muitas instâncias da sua classe, portanto, problemas de desempenho. Os métodos deveriam ter sido declarados fora do escopo do construtor. Meu comentário foi mais uma explicação para as desvantagens de sua solução do que uma crítica.Uma abordagem diferente para "privado"
Em vez de lutar contra o fato de que atualmente a visibilidade privada não está disponível no ES6, decidi adotar uma abordagem mais prática que funcionaria bem se o seu IDE oferecer suporte ao JSDoc (por exemplo, Webstorm). A ideia é usar a
@private
tag . No que diz respeito ao desenvolvimento, o IDE impedirá que você acesse qualquer membro privado de fora de sua classe. Funciona muito bem para mim e tem sido realmente útil para ocultar métodos internos, de modo que o recurso de preenchimento automático me mostra exatamente o que a classe realmente pretendia expor. Aqui está um exemplo:fonte
@private
comentário não pode evitá-los, é apenas um Recurso para geração de documentação e você é IDE.WeakMap
Object.getOwnPropertySymbols
)Primeiro, defina uma função para agrupar o WeakMap:
Em seguida, construa uma referência fora da sua classe:
Nota: a classe não é suportada pelo IE11, mas parece mais limpa no exemplo.
fonte
Oh, tantas soluções exóticas! Normalmente não me importo com privacidade, então uso "pseudo privacidade", como é dito aqui . Mas se me importo (se houver alguns requisitos especiais para isso) eu uso algo como neste exemplo:
Outra implementação possível da função (construtor)
Job
:fonte
Pessoalmente, gosto da proposta do operador bind
::
e a combinaria com a solução @ d13 mencionada, mas, por enquanto, atenha-se à resposta da @ d13, onde você usa aexport
palavra - chave para sua classe e coloca as funções privadas no módulo.há mais uma solução difícil que não foi mencionada aqui a seguir, é uma abordagem mais funcional e permitiria que ele tivesse todos os métodos / props privados da classe.
Private.js
Test.js
comentários sobre isso seriam apreciados.
fonte
Me deparei com este post ao procurar a melhor prática para "dados privados para aulas". Foi mencionado que alguns dos padrões teriam problemas de desempenho.
Eu montei alguns testes jsperf com base nos quatro padrões principais do livro on-line "Explorando o ES6":
http://exploringjs.com/es6/ch_classes.html#sec_private-data-for-classes
Os testes podem ser encontrados aqui:
https://jsperf.com/private-data-for-classes
No Chrome 63.0.3239 / Mac OS X 10.11.6, os padrões com melhor desempenho eram "Dados privados por meio de ambientes de construtores" e "Dados privados por meio de uma convenção de nomenclatura". Para mim, o Safari teve um bom desempenho no WeakMap, mas o Chrome não tão bem.
Não conheço o impacto da memória, mas o padrão para "ambientes construtores", que alguns haviam avisado que seria um problema de desempenho, foi muito eficiente.
Os 4 padrões básicos são:
Dados privados via ambientes construtores
Dados privados via ambientes construtores 2
Dados privados por meio de uma convenção de nomenclatura
Dados privados via WeakMaps
Dados privados via símbolos
fonte
Eu acredito que é possível obter o 'melhor dos dois mundos' usando fechamentos dentro de construtores. Existem duas variações:
Todos os membros dos dados são privados
Alguns membros são privados
NOTA: Isso é reconhecidamente feio. Se você conhece uma solução melhor, edite esta resposta.
fonte
De fato, é possível usar Símbolos e Proxies. Você usa os símbolos no escopo da classe e define dois desvios em um proxy: um para o protótipo de classe, para que o Reflect.ownKeys (instance) ou Object.getOwnPropertySymbols não divulgue seus símbolos, o outro é para o próprio construtor portanto, quando
new ClassName(attrs)
for chamada, a instância retornada será interceptada e terá os próprios símbolos de propriedades bloqueados. Aqui está o código:Reflect.ownKeys()
funciona assim:Object.getOwnPropertyNames(myObj).concat(Object.getOwnPropertySymbols(myObj))
é por isso que precisamos de uma armadilha para esses objetos.fonte
Mesmo o Typecript não pode fazer isso. Da documentação deles :
Mas transpiled em seu playground isso dá:
Portanto, a palavra-chave "particular" é ineficaz.
fonte
Chegando muito tarde para esta festa, mas eu acertei a pergunta do OP em uma pesquisa, então ... Sim, você pode ter propriedades particulares envolvendo a declaração de classe em um fechamento
Há um exemplo de como eu tenho métodos particulares neste codepen . No snippet abaixo, a classe Subscribable possui duas funções 'private'
process
eprocessCallbacks
. Quaisquer propriedades podem ser adicionadas dessa maneira e são mantidas em sigilo pelo uso do fechamento. A privacidade da IMO é uma necessidade rara, se as preocupações estiverem bem separadas e o Javascript não precisar ficar inchado, adicionando mais sintaxe quando um fechamento faz o trabalho corretamente.Eu gosto dessa abordagem porque ela separa bem as preocupações e mantém as coisas realmente privadas. A única desvantagem é a necessidade de usar 'self' (ou algo semelhante) para se referir a 'this' no conteúdo privado.
fonte
Acho que a resposta de Benjamin é provavelmente a melhor para a maioria dos casos, até que a linguagem suporte nativamente variáveis explicitamente privadas.
No entanto, se por algum motivo você precisar impedir o acesso
Object.getOwnPropertySymbols()
, um método que considerei usar é anexar uma propriedade exclusiva, não configurável, não enumerável e não gravável, que pode ser usada como um identificador de propriedade para cada objeto em construção (como um exclusivoSymbol
, se você ainda não tiver outra propriedade exclusiva, como umid
). Em seguida, basta manter um mapa das variáveis 'privadas' de cada objeto usando esse identificador.A vantagem potencial dessa abordagem sobre o uso de a
WeakMap
é um tempo de acesso mais rápido se o desempenho se tornar uma preocupação.fonte
destroy()
método que deve ser chamado pelo código using sempre que um objeto precisar ser removido.Sim, totalmente pode, e muito facilmente também. Isso é feito expondo suas variáveis e funções privadas retornando o gráfico de objeto de protótipo no construtor. Isso não é novidade, mas tome um pouco de tempo para entender a elegância disso. Dessa forma, não utiliza escopos globais ou mapas fracos. É uma forma de reflexão embutida na linguagem. Dependendo de como você aproveita isso; pode-se forçar uma exceção que interrompe a pilha de chamadas ou enterrar a exceção como um
undefined
. Isso é iniciado abaixo e pode ler mais sobre esses recursos aquifonte
fonte
console.log(instance.property)
deve jogar ou lhe dar indefinido, não devolver "teste".Outra maneira semelhante às duas últimas postadas
fonte
A maioria das respostas diz que é impossível ou exige que você use um WeakMap ou Symbol, que são recursos do ES6 que provavelmente exigiriam polyfills. No entanto, há outra maneira! Confira isso:
Eu chamo esse padrão de acessador de método . A idéia essencial é que tenhamos um fechamento , uma chave dentro do fechamento, e criamos um objeto privado (no construtor) que só pode ser acessado se você tiver a chave .
Se você estiver interessado, pode ler mais sobre isso no meu artigo . Usando esse método, você pode criar propriedades por objeto que não podem ser acessadas fora do fechamento. Portanto, você pode usá-los no construtor ou protótipo, mas não em nenhum outro lugar. Não vi esse método usado em nenhum lugar, mas acho que é realmente poderoso.
fonte
Consulte esta resposta para obter uma solução 'classe' limpa e simples com uma interface pública e privada e suporte para composição
fonte
Encontrei uma solução muito simples, basta usar
Object.freeze()
. Obviamente, o problema é que você não pode adicionar nada ao objeto posteriormente.fonte
setName(name) { this.name = name; }
Eu uso esse padrão e sempre funcionou para mim
fonte
Na verdade é possível.
1. Primeiro, crie a classe e no construtor retorne a
_public
função chamada .2. Na
_public
função chamada , passe athis
referência (para obter acesso a todos os métodos e props privados) e todos os argumentos deconstructor
(que serão passadosnew Names()
)3. No
_public
escopo da função, também há aNames
classe com acessothis
(_this ) referência daNames
classe privadafonte
Você pode tentar isso https://www.npmjs.com/package/private-members
Este pacote salvará os membros por instância.
fonte