JavaScript utiliza la herencia prototípica: cada objeto hereda propiedades y métodos de su objeto prototipo.
la clase tradicional como blueprint para crear objetos, utilizada en lenguajes como Java o Swift, no existe en JavaScript. La herencia prototípica solo trata de objetos.
la herencia prototípica puede emular la herencia de clase clásica. Para llevar las clases tradicionales a JavaScript, el estándar ES2015 introduce la sintaxis class
: un azúcar sintáctico sobre la herencia prototípica.,
este post te familiariza con las clases de JavaScript: cómo definir una clase, inicializar la instancia, Definir campos y métodos, comprender los campos privados y públicos, comprender los campos y métodos estáticos.
1. Definición: la palabra clave class
La palabra clave especial class
define una clase en JavaScript:
class User { // The body of class}
El código anterior define una clase User
. Las llaves { }
delimitan el cuerpo de la clase. Tenga en cuenta que esta sintaxis se denomina declaración de clase.,
no está obligado a indicar el nombre de la clase. Al usar una expresión de clase, puede asignar la clase a una variable:
const UserClass = class { // The body of class};
Puede exportar fácilmente una clase como parte de un módulo ES2015. Esta es la sintaxis para una exportación predeterminada:
export default class User { // The body of class}
Y un llamado a la exportación:
export class User { // The body of class}
La clase se vuelve útil cuando se crea una instancia de la clase. Una instancia es un objeto que contiene datos y comportamientos descritos por la clase.,
El new
operador crea una instancia de la clase en JavaScript: instance = new Class()
.
Por ejemplo, puede crear una instancia de la etiqueta User
clase de uso de la etiqueta new
usuario:
const myUser = new User();
new User()
crea una instancia de la etiqueta User
clase.
2. Inicialización: constructor()
constructor(param1, param2, ...)
es un método especial en el cuerpo de una clase que inicializa la instancia., Ese es el lugar donde se establecen los valores iniciales para los campos, o hacer cualquier tipo de configuración de objetos.
En el siguiente ejemplo, el constructor establece el valor inicial del campo name
:
class User { constructor(name) { this.name = name; }}
User
‘s constructor tiene un parámetro name
, que se utiliza para establecer el valor inicial del campo this.name
.
dentro del constructor this
el valor es igual a la instancia recién creada.,
Los argumentos utilizados para crear instancias de la clase se convierten en los parámetros del constructor:
class User { constructor(name) { name; // => 'Jon Snow' this.name = name; }}const user = new User('Jon Snow');
name
parámetro dentro del constructor tiene el valor de 'Jon Snow'
.
si no define un constructor para la clase, se crea uno predeterminado. El constructor predeterminado es una función vacía, que no modifica la instancia.
al mismo tiempo, una clase JavaScript puede tener hasta un constructor.
3. Fields
Los campos de clase son variables que contienen información., Los campos se pueden adjuntar a 2 entidades:
- campos en la instancia de clase
- campos en la clase misma (también conocida como estática)
Los campos también tienen 2 niveles de Accesibilidad:
- público: el campo es accesible en cualquier lugar
- privado: el campo es accesible solo dentro del cuerpo de la clase
3.1 campos de instancia pública
en el fragmento de código anterior:
class User { constructor(name) { this.name = name; }}
la expresión this.name = name
crea un campo de instancia name
y le asigna un valor inicial.,
Más tarde puede acceder a name
campo usando un accessor de propiedad:
const user = new User('Jon Snow');user.name; // => 'Jon Snow'
name
es un campo público porque puede acceder a él fuera del User
cuerpo de clase.
cuando los campos se crean implícitamente dentro del constructor, como en el escenario anterior, podría ser difícil comprender la lista de campos. Tienes que descifrarlos desde el código del constructor.
un mejor enfoque es declarar explícitamente los campos de clase., No importa lo que haga el constructor, la instancia siempre tiene el mismo conjunto de campos.
la propuesta class fields le permite definir los campos dentro del cuerpo de la clase. Además, puede indicar el valor inicial de inmediato:
class SomeClass { field1; field2 = 'Initial value'; // ...}
Vamos a modificar el User
clase y declarar un campo público name
:
class User { name; constructor(name) { this.name = name; }}const user = new User('Jon Snow');user.name; // => 'Jon Snow'
name;
en el interior del cuerpo de la clase se declara un campo público name
.,
Los campos públicos declarados de esta manera son expresivos: un vistazo rápido a las declaraciones de Campos es suficiente para comprender la estructura de datos de la clase.
Además, el campo de clase se puede inicializar de inmediato en la declaración.
class User { name = 'Unknown'; constructor() { // No initialization }}const user = new User();user.name; // => 'Unknown'
name = 'Unknown'
dentro del cuerpo de la clase declara un campo name
y lo inicializa con el valor 'Unknown'
.
no hay restricción en el acceso o actualización de los campos públicos., Puede leer y asignar valores a campos públicos dentro del constructor, métodos y fuera de la clase.
3.2 campos de instancia privada
La encapsulación es un concepto importante que le permite ocultar los detalles internos de una clase. Alguien que usa una clase encapsulada depende solo de la interfaz pública que la clase proporciona, y no se acopla a los detalles de implementación de la clase.
Las clases organizadas con encapsulación en mente son más fáciles de actualizar cuando cambian los detalles de la implementación.,
una buena manera de ocultar los datos internos de un objeto es utilizar los campos privados. Estos son los campos que se pueden leer y cambiar solo dentro de la clase a la que pertenecen. El mundo exterior de la clase no puede cambiar los campos privados directamente.
Los campos privados sólo son accesibles dentro del cuerpo de la clase.
Prefijo el nombre del campo con el símbolo especial #
para facilitar privado, por ejemplo #myField
., El prefijo #
debe mantenerse cada vez que trabaje con el campo: declararlo, leerlo o modificarlo.
Vamos a asegurarnos de que el campo #name
se puede configurar una vez en la instancia de inicialización:
#name
es un campo privado. Puede acceder y modificar #name
dentro del cuerpo del User
. El método getName()
(más sobre los métodos en la siguiente sección) puede acceder al campo privado #name
.,
pero si intenta acceder al campo privado #name
fuera del cuerpo de la clase User
, se lanza un error de sintaxis: SyntaxError: Private field '#name' must be declared in an enclosing class
.
3.3 campos estáticos públicos
También puede definir campos en la propia clase: los campos estáticos. Estos son útiles para definir constantes de clase o almacenar información específica de la clase.
para crear campos estáticos en una clase JavaScript, utilice la palabra clave especial static
seguido del nombre del campo: static myStaticField
.,
vamos a añadir un nuevo campo type
que indica el tipo de usuario: admin o regular. Los campos estáticos TYPE_ADMIN
y TYPE_REGULAR
son constantes útiles para diferenciar los tipos de usuario:
static TYPE_ADMIN
y static TYPE_REGULAR
definen variables estáticas dentro del User
class. Para acceder a los campos estáticos, debe usar la clase seguida del nombre del campo: User.TYPE_ADMIN
y User.TYPE_REGULAR
.
3.,4 campos estáticos privados
a veces incluso los campos estáticos son un detalle de implementación que le gustaría ocultar. En este sentido, puede hacer que los campos estáticos sean privados.
para hacer privado el campo estático, prefije el nombre del campo con #
símbolo especial: static #myPrivateStaticField
.
supongamos que desea limitar el número de instancias de la clase User
., Para ocultar los detalles sobre los límites de instancias, puede crear los campos estáticos privados:
el campo estático User.#MAX_INSTANCES
establece el número máximo de instancias permitidas, mientras que User.#instances
el campo estático cuenta el número real de instancias.
Estos campos estáticos privados solo son accesibles dentro de la clase User
. Nada del mundo externo puede interferir con el mecanismo de límites: ese es el beneficio de la encapsulación.
4. Métodos
Los campos contienen datos., Pero la capacidad de modificar datos es realizada por funciones especiales que son parte de la clase: los métodos.
Las Clases de JavaScript admiten métodos de instancia y estáticos.
4.1 Métodos de instancia
los métodos de instancia pueden acceder y modificar los datos de instancia. Los métodos de instancia pueden llamar a otros métodos de instancia, así como a cualquier método estático.,
por ejemplo, vamos a definir un método getName()
que devuelve el nombre en el User
class:
en un método de clase, así como en el constructor, this
el valor es igual a la instancia de clase. Use this
para acceder a los datos de instancia: this.field
, o incluso llame a otros métodos: this.method()
.,
Vamos a agregar un nuevo método de nameContains(str)
que tiene un parámetro y llama a otro método:
nameContains(str) { ... }
es un método de User
clase que acepta un parámetro str
. Más que eso, ejecuta otro método de la instancia this.getName()
para obtener el nombre del usuario.
Un método también puede ser privado. Para hacer el prefijo privado del método su nombre con #
.
Vamos a hacer getName()
método privado:
#getName()
es un método privado., Dentro del método nameContains(str)
llamar a un método privado de tal manera: this.#getName()
.
siendo privado,#getName()
no se puede llamar fuera del cuerpo de la claseUser
.
4.2 Getters y setters
el getter y el setter imitan el campo regular, pero con más control sobre cómo se accede y cambia el campo.
el getter se ejecuta en un intento de obtener el valor del campo, mientras que setter en un intento de establecer un valor.,
Para asegurarse de que el name
propiedad de la etiqueta User
no puede estar vacío, vamos a envolver el campo privado #nameValue
en un getter y setter:
get name() {...}
captador se ejecuta cuando el acceso al valor del campo: user.name
.
4.3 métodos Estáticos
Los métodos estáticos son funciones conectada directamente a la clase. Tienen lógica relacionada con la clase, en lugar de con la instancia de la clase.,
para crear un método estático use la palabra clave especial static
seguida de una sintaxis de método regular: static myStaticMethod() { ... }
.
cuando se trabaja con métodos estáticos, hay 2 reglas simples para recordar:
- un método estático puede acceder a campos estáticos
- un método estático no puede acceder a campos de instancia.
Por ejemplo, vamos a crear un método estático que detecta si un usuario con un nombre específico ya fue tomado.,
isNameTaken()
es un método estático que utiliza la estática campo privado User.#takenNames
para comprobar tomado nombres.
5. Herencia: extiende
las clases en JavaScript admiten herencia única usando la palabra clave extends
.
En la expresión class Child extends Parent { }
Child
clase hereda de Parent
el constructor, campos y métodos.
por ejemplo, vamos a crear una nueva clase secundaria ContentWriter
que extiende la clase principal User
.,
ContentWriter
hereda de la etiqueta User
el constructor, el método de getName()
y el campo name
. Así, el ContentWriter
clase declara un nuevo campo posts
.
tenga en cuenta que los miembros privados de una clase padre no son heredados por la clase hija.
5.1 Constructor Padre: super () en constructor ()
si desea llamar al constructor padre en una clase hija, necesita usar la función especial super()
disponible en el constructor hijo.,
Por ejemplo, vamos a hacer ContentWriter
llamada al constructor el constructor padre de User
, así como inicializar los postes de campo:
super(name)
dentro de la clase ContentWriter
ejecuta el constructor de la clase padre User
.
tenga en cuenta que dentro del constructor hijo debe ejecutar super()
antes de usar la palabra clave this
. Llamando a super()
se asegura de que el constructor padre inicialice la instancia.,
class Child extends Parent { constructor(value1, value2) { // Does not work! this.prop2 = value2; super(value1); }}
5.2 instancia principal: super en métodos
Si quieres acceder al método padre en el interior de un niño, puede utilizar el acceso directo especial super
.
getName()
del niño de la clase ContentWriter
accede al método super.getName()
directamente desde la clase principal User
.
Esta característica se denomina método primordial.
tenga en cuenta que puede usar super
con métodos estáticos también, para acceder a los métodos estáticos del Padre.
6., Object type checking: instanceof
object instanceof Class
is the operator that determines if object
is an instance of Class
.
Let’s see instanceof
operator in action:
user
is an instance of User
class, user instanceof User
evaluates to true
.
The empty object {}
is not an instance of User
, correspondingly obj instanceof User
is false
.,
instanceof
es polimórfico: el operador detecta un hijo como una instancia de la clase padre.
writer
es una instancia de la clase hija ContentWriter
. El operador writer instanceof ContentWriter
evalúa a true
.
al mismo tiempo ContentWriter
es una clase secundaria de User
. Así writer instanceof User
evalúa a true
así.
¿Qué pasa si desea determinar la clase exacta de la instancia?, Puede utilizar la etiqueta constructor
propiedad y comparar directamente con la clase:
writer.constructor === ContentWriter; // => truewriter.constructor === User; // => false
7. Clases y prototipos
debo decir que la sintaxis de clase en JavaScript hace un gran trabajo para abstraerse de la herencia prototípica. Para describir la sintaxis class
ni siquiera he usado el término prototipo.
pero las clases se construyen sobre la herencia prototípica. Cada clase es una función, y crea una instancia cuando se invoca como constructor.
los dos fragmentos de código siguientes son equivalentes.,
la versión de la clase:
la versión que usa prototype:
la sintaxis de la clase es mucho más fácil de trabajar si está familiarizado con el mecanismo de herencia clásico de los lenguajes Java o Swift.
de todos modos, incluso si utiliza sintaxis de clase en JavaScript, le recomiendo tener una buena comprensión de la herencia prototípica.
8. Disponibilidad de las características de clase
las características de clase presentadas en este post están distribuidas en ES2015 y las propuestas en la etapa 3.,
a finales de 2019, las entidades de clase se dividen entre:
- Los campos de instancia pública y privada forman parte de la propuesta de campos de clase
- Los métodos de instancia privada y los accesores forman parte de la propuesta de métodos privados de clase
- Los campos estáticos públicos y privados y los métodos estáticos privados forman parte de la propuesta de características estáticas de clase
- El resto forma parte del estándar ES2015.
9. Conclusión
Las Clases JavaScript inicializan instancias con Constructores, definen campos y métodos., Puede adjuntar campos y métodos incluso en la propia clase usando la palabra clave static
.
La herencia se logra usando extends
palabra clave: puede crear fácilmente una clase hija de un padre. super
la palabra clave se usa para acceder a la clase padre desde una clase hija.
para aprovechar la encapsulación, haga que los campos y métodos sean privados para ocultar los detalles internos de sus clases. Los nombres de los campos y métodos privados deben comenzar con #
.,
las clases en JavaScript se vuelven cada vez más convenientes de usar.
¿Qué opinas sobre usar #
para prefijar propiedades privadas?