En TypeScript 3.8+, ¿cuáles son las diferencias entre usar la private
palabra clave para marcar un miembro como privado?
class PrivateKeywordClass {
private value = 1;
}
Y utilizando los #
campos privados propuestos para JavaScript :
class PrivateFieldClass {
#value = 1;
}
¿Debería preferir uno sobre el otro?
javascript
typescript
class
encapsulation
Matt Bierner
fuente
fuente
Respuestas:
Palabra clave privada
La palabra clave privada en TypeScript es una anotación en tiempo de compilación . Le dice al compilador que una propiedad solo debe ser accesible dentro de esa clase:
Sin embargo, la verificación del tiempo de compilación se puede omitir fácilmente, por ejemplo, desechando la información de tipo:
La
private
palabra clave tampoco se aplica en tiempo de ejecuciónJavaScript emitido
Al compilar TypeScript en JavaScript, la
private
palabra clave simplemente se elimina:Se convierte en:
A partir de esto, puede ver por qué la
private
palabra clave no ofrece ninguna protección de tiempo de ejecución: en el JavaScript generado es solo una propiedad JavaScript normal.Campos privados
Los campos privados aseguran que las propiedades se mantengan privadas en tiempo de ejecución :
TypeScript también generará un error de tiempo de compilación si intenta usar un campo privado fuera de una clase:
Los campos privados provienen de una propuesta de JavaScript y también funcionan en JavaScript normal.
JavaScript emitido
Si usa campos privados en TypeScript y está apuntando a versiones anteriores de JavaScript para su salida, como
es6
oes2018
, TypeScript intentará generar código que emule el comportamiento en tiempo de ejecución de los campos privadosSi está apuntando
esnext
, TypeScript emitirá el campo privado:¿Cuál debo usar?
Depende de lo que intentes lograr.
La
private
palabra clave es un buen valor predeterminado. Cumple lo que fue diseñado para lograr y ha sido utilizado con éxito por los desarrolladores de TypeScript durante años. Y si tiene una base de código existente, no necesita cambiar todo su código para usar campos privados. Esto es especialmente cierto si no está apuntandoesnext
, ya que el JS que TS emite para campos privados puede tener un impacto en el rendimiento. También tenga en cuenta que los campos privados tienen otras diferencias sutiles pero importantes de laprivate
palabra claveSin embargo, si necesita exigir privacidad en tiempo de ejecución o está generando
esnext
JavaScript, debe utilizar campos privados.También tenga en cuenta que las convenciones de organización / comunidad sobre el uso de uno u otro también evolucionarán a medida que los campos privados se generalicen dentro de los ecosistemas JavaScript / TypeScript
Otras diferencias de nota
Los campos privados no son devueltos por
Object.getOwnPropertyNames
métodos similares.Los campos privados no son serializados por
JSON.stringify
Hay casos importantes de importancia en torno a la herencia.
TypeScript, por ejemplo, prohíbe declarar una propiedad privada en una subclase con el mismo nombre que una propiedad privada en la superclase.
Esto no es cierto con los campos privados:
Una
private
propiedad privada de palabra clave sin un inicializador no generará una declaración de propiedad en el JavaScript emitido:Compila a:
Mientras que los campos privados siempre generan una declaración de propiedad:
Compila a (cuando apunta
esnext
):Otras lecturas:
fuente
Casos de uso:
#
-campos privadosPrefacio:
#
-privado, privado privado, privado en tiempo de ejecuciónTiempo de compilación y privacidad en tiempo de ejecución
#
Privadas campos proporcionan el tiempo de compilación y privacidad en tiempo de ejecución, lo que no es "piratear". Es un mecanismo para evitar el acceso a un miembro desde fuera del cuerpo de la clase de manera directa .Herencia de clase segura
#
-los campos privados obtienen un alcance único. Las jerarquías de clase se pueden implementar sin sobrescribir accidentalmente propiedades privadas con nombres iguales.Afortunadamente, el compilador de TS emite un error cuando las
private
propiedades están en peligro de sobrescribirse (consulte este ejemplo ). Pero debido a la naturaleza de una función de tiempo de compilación, todo es posible en tiempo de ejecución, dado que los errores de compilación son ignorados y / o se utiliza el código JS emitido.Bibliotecas externas
Los autores de la biblioteca pueden refactorizar
#
identificadores privados sin causar un cambio importante para los clientes. Los usuarios de la biblioteca en el otro lado están protegidos de acceder a los campos internos.La API de JS omite
#
campos privadosLas funciones y métodos JS incorporados ignoran los
#
campos privados. Esto puede dar como resultado una selección de propiedades más predecible en tiempo de ejecución. Ejemplos:Object.keys
,Object.entries
,JSON.stringify
,for..in
bucle y otros ( ejemplo de código ; véase también de Matt Bierner respuesta ):Casos de uso:
private
palabra clavePrefacio:
private
palabra clave en documentos de TSAcceso a la clase interna API y estado (privacidad solo en tiempo de compilación)
private
Los miembros de una clase son propiedades convencionales en tiempo de ejecución. Podemos utilizar esta flexibilidad para acceder a la API interna de la clase o al estado desde el exterior. Para satisfacer las comprobaciones del compilador, mecanismos como aserciones de tipo, acceso a propiedades dinámicas o@ts-ignore
se pueden usar entre otros.Ejemplo con aserción de tipo (
as
/<>
) yany
asignación de variable con tipo :TS incluso permite el acceso a propiedades dinámicas de un
private
miembro con una escotilla de escape :¿Dónde puede tener sentido el acceso privado? (1) pruebas unitarias, (2) situaciones de depuración / registro u (3) otros escenarios de casos avanzados con clases internas del proyecto (lista abierta).
El acceso a las variables internas es un poco contradictorio; de lo contrario, no las habría hecho
private
en primer lugar. Para dar un ejemplo, se supone que las pruebas unitarias son cuadros negros / grises con campos privados ocultos como detalles de implementación. Sin embargo, en la práctica, puede haber enfoques válidos de un caso a otro.Disponible en todos los entornos ES
Los
private
modificadores TS se pueden usar con todos los objetivos ES.#
-los campos privados solo están disponibles paratarget
ES2015
/ES6
o superior. En ES6 +,WeakMap
se usa internamente como implementación de nivel inferior (ver aquí ). Los#
campos nativos- privados actualmente requierentarget
esnext
.Consistencia y compatibilidad
Los equipos pueden usar pautas de codificación y reglas de interfaz para imponer el uso
private
como el único modificador de acceso. Esta restricción puede ayudar con la coherencia y evitar confusiones con la#
notación de campo privado de una manera compatible con versiones anteriores.Si es necesario, las propiedades de los parámetros (abreviatura de asignación de constructor) son un show stopper. Solo se pueden usar con
private
palabras clave y todavía no hay planes para implementarlas para#
campos privados.Otras razones
private
podría proporcionar un mejor rendimiento en tiempo de ejecución en algunos casos de reducción de nivel (ver aquí ).private
prefieren la notación de palabras clave 😊.Nota sobre ambos
Ambos enfoques crean algún tipo de tipo nominal o de marca en tiempo de compilación.
Además, ambos permiten el acceso entre instancias: una instancia de clase
A
puede acceder a miembros privados de otrasA
instancias:Fuentes
fuente