No TypeScript 3.8+, quais são as diferenças entre usar a private
palavra-chave para marcar um membro como privado:
class PrivateKeywordClass {
private value = 1;
}
E usando os #
campos particulares propostos para JavaScript :
class PrivateFieldClass {
#value = 1;
}
Devo preferir um ao outro?
javascript
typescript
class
encapsulation
Matt Bierner
fonte
fonte
Respostas:
Palavra-chave privada
A palavra-chave privada no TypeScript é uma anotação em tempo de compilação . Diz ao compilador que uma propriedade só deve ser acessível dentro dessa classe:
No entanto, a verificação do tempo de compilação pode ser facilmente ignorada, por exemplo, descartando as informações de tipo:
A
private
palavra-chave também não é aplicada no tempo de execuçãoJavaScript emitido
Ao compilar o TypeScript para JavaScript, a
private
palavra-chave é simplesmente removida:Torna-se:
A partir disso, você pode ver por que a
private
palavra - chave não oferece proteção de tempo de execução: no JavaScript gerado, é apenas uma propriedade JavaScript normal.Campos privados
Os campos privados garantem que as propriedades sejam mantidas privadas em tempo de execução :
O TypeScript também emitirá um erro de tempo de compilação se você tentar usar um campo privado fora de uma classe:
Os campos particulares são provenientes de uma proposta JavaScript e também funcionam em JavaScript normal.
JavaScript emitido
Se você usa campos particulares no TypeScript e está direcionando versões mais antigas do JavaScript para sua saída, como
es6
oues2018
, o TypeScript tentará gerar código que emule o comportamento do tempo de execução dos campos privadosSe você estiver direcionando
esnext
, o TypeScript emitirá o campo privado:Qual devo usar?
Depende do que você está tentando alcançar.
A
private
palavra-chave é um ótimo padrão. Ele realiza o que foi projetado para realizar e tem sido usado com sucesso pelos desenvolvedores do TypeScript há anos. E se você possui uma base de código existente, não precisa alternar todo o seu código para usar campos particulares. Isso é especialmente verdadeiro se você não estiver direcionandoesnext
, pois o JS que o TS emite para campos particulares pode ter um impacto no desempenho. Lembre-se também de que os campos particulares têm outras diferenças sutis, mas importantes, doprivate
palavra chaveNo entanto, se você precisar impor a privacidade do tempo de execução ou estiver produzindo
esnext
JavaScript, deverá usar campos privados.Lembre-se também de que as convenções da organização / comunidade sobre o uso de um ou de outro também evoluirão à medida que os campos privados se tornarem mais difundidos nos ecossistemas JavaScript / TypeScript
Outras diferenças de nota
Campos privados não são retornados por
Object.getOwnPropertyNames
métodos semelhantesOs campos particulares não são serializados por
JSON.stringify
Existem casos importantes em torno da herança.
O TypeScript, por exemplo, proíbe declarar uma propriedade privada em uma subclasse com o mesmo nome que uma propriedade privada na superclasse.
Isso não é verdade com campos particulares:
Uma
private
propriedade privada de palavra-chave sem um inicializador não gerará uma declaração de propriedade no JavaScript emitido:Compila para:
Enquanto os campos privados sempre geram uma declaração de propriedade:
Compila para (quando segmentar
esnext
):Leitura adicional:
fonte
Casos de uso:
#
-private fieldsPrefácio:
#
privado, privado, privado, tempo de execuçãoTempo de compilação e privacidade de tempo de execução
#
campos -Privadas fornecer tempo de compilação e privacidade de tempo de execução, o que não é "hackable". É um mecanismo para impedir o acesso a um membro de fora do corpo da classe de maneira direta .Herança de classe segura
#
Os campos privados recebem um escopo exclusivo. As hierarquias de classe podem ser implementadas sem substituições acidentais de propriedades particulares com nomes iguais.Felizmente, o compilador TS emite um erro quando as
private
propriedades correm o risco de serem substituídas (consulte este exemplo ). Porém, devido à natureza de um recurso de tempo de compilação, tudo ainda é possível no tempo de execução, dado que os erros de compilação são ignorados e / ou é emitido o código JS utilizado.Bibliotecas externas
Os autores da biblioteca podem refatorar
#
identificadores privados sem causar uma alteração de interrupção para os clientes. Os usuários da biblioteca do outro lado estão protegidos contra o acesso a campos internos.A API JS omite os
#
campos -privateAs funções e métodos JS internos ignoram os
#
campos -private. Isso pode resultar em uma seleção de propriedade mais previsível em tempo de execução. Exemplos:Object.keys
,Object.entries
,JSON.stringify
,for..in
loop e outros ( exemplo de código ; ver também de Matt Bierner resposta ):Casos de uso:
private
keywordPrefácio:
private
palavra-chave nos documentos do TSAcesso à API e ao estado da classe interna (privacidade apenas em tempo de compilação)
private
membros de uma classe são propriedades convencionais em tempo de execução. Podemos usar essa flexibilidade para acessar a API ou o estado interno da classe de fora. Para satisfazer as verificações do compilador, mecanismos como asserções de tipo, acesso dinâmico à propriedade ou@ts-ignore
podem ser usados entre outros.Exemplo com asserção de tipo (
as
/<>
) eany
atribuição de variável digitada:O TS ainda permite o acesso dinâmico à propriedade de um
private
membro com uma saída de escape :Onde o acesso privado pode fazer sentido? (1) testes de unidade, (2) situações de depuração / registro em log ou (3) outros cenários de casos avançados com classes internas do projeto (lista aberta).
O acesso a variáveis internas é um pouco contraditório - caso contrário, você não as teria criado
private
em primeiro lugar. Para dar um exemplo, os testes de unidade devem ser caixas pretas / cinza com campos particulares ocultos como detalhes da implementação. Na prática, porém, pode haver abordagens válidas de caso para caso.Disponível em todos os ambientes ES
private
Modificadores de TS podem ser usados com todos os destinos de ES.#
Os campos privados estão disponíveis apenas paratarget
ES2015
/ES6
ou superiores. No ES6 +,WeakMap
é usado internamente como implementação de nível inferior (veja aqui ).#
Atualmente, os campos nativos particulares requeremtarget
esnext
.Consistência e compatibilidade
As equipes podem usar diretrizes de codificação e regras de linter para impor o uso
private
como o único modificador de acesso. Essa restrição pode ajudar na consistência e evitar confusão com a#
notação de campo -private de uma maneira compatível com versões anteriores.Se necessário, as propriedades dos parâmetros (abreviação de atribuição do construtor) são um limitador de exibição. Eles podem ser usados apenas com a
private
palavra - chave e ainda não há planos para implementá-los em#
campos privados.Outras razões
private
pode fornecer melhor desempenho em tempo de execução em alguns casos de nível inferior (veja aqui ).private
notação de palavras - chave 😊.Nota sobre ambos
Ambas as abordagens criam algum tipo de tipo nominal ou de marca no momento da compilação.
Além disso, ambos permitem acesso entre instâncias: uma instância da classe
A
pode acessar membros particulares de outrasA
instâncias:Fontes
fonte