JavaScript es un lenguaje basado en prototipos y cada objeto en él tiene una propiedad interna oculta llamada [[Prototype]]
que puede usarse para extender propiedades y métodos de objetos. Puede obtener más información sobre los prototipos de nuestro tutorial Información sobre los prototipos y la herencia en JavaScript.
Hasta hace poco, los desarrolladores esforzados usaban funciones constructoras para imitar un patrón de diseño orientado a objetos en JavaScript. La especificación de lenguaje ECMAScript 2015, a menudo denominada ES6, introdujo clases en el lenguaje JavaScript. Las clases de JavaScript no ofrecen realmente una funcionalidad adicional y a menudo se describen como elementos que aportan “azúcar sintáctico" en comparación con los prototipos y la herencia, ya que ofrecen una sintaxis más limpia y elegante. Debido a que otros lenguajes de programación usan clases, la sintaxis de clase de JavaScript permite que los desarrolladores alternen lenguajes de forma más directa.
Una clase de JavaScript es un tipo de función. Las clases se declaran con la palabra clave class
. Usaremos sintaxis de expresión de función para inicializar una sintaxis de expresión de función y clase para inicializar una clase.
Podemos acceder a [[Prototype]]
de un objeto usando el métodoObject.getPrototypeOf()
. Usaremos eso para probar la función vacía que creamos.
Outputƒ () { [native code] }
También podemos usar ese método en la clase que acabamos de crear.
Outputƒ () { [native code] }
El código declarado con function
y class
muestra una función [[Prototype]]
. Con prototipos, cualquier función puede convertirse en una instancia de constructor mediane la palabra clave new
.
Outputx {}
constructor: ƒ ()
Esto se aplica a clases también.
Outputy {}
constructor: class
Estos ejemplos de constructores de prototipos, de lo contrario, están vacíos. Sin embargo, podemos ver que debajo de la sintaxis ambos métodos logran el mismo resultado final.
En el tutorial de prototipos y herencia, confeccionamos un ejemplo basado en la creación de personajes en un juego de roles basado en texto. Continuaremos con ese ejemplo aquí para actualizar la sintaxis de funciones a clases.
Una función constructora se inicializa con varios parámetros que se asignarían como propiedades de this
, en alusión a la propia función. La primera letra del identificador sería mayúscula por convención.
Cuando traducimos esto a la sintaxis de clase, que se muestra a continuación, vemos que su estructura es bastante similar.
Sabemos que una función constructora está pensada para ser un esquema de objeto por el uso de mayúscula en la primera letra del inicializador (opcional) y a través de la familiaridad con la sintaxis. La palabra clave class
comunica de una manera más directa el objetivo de nuestra función.
La única diferencia en la sintaxis de la inicialización tiene que ver con el uso de la palabra clave class
en lugar de function
, y con la asignación de las propiedades dentro de un método constructor()
.
La práctica común con funciones constructoras consiste en asignar métodos directamente a prototype
en lugar de hacerlo con la initialización, como se aprecia en el método greet()
a continuación.
Con clases, esta sintaxis se simplifica y el método puede agregarse directamente a las clases. Al usar la abreviatura de definición de método introducida en ES6, se logra una concisión aun mayor al definir un método.
Observemos estas propiedades y métodos en acción. Crearemos una nueva instancia de Hero
usando la palabra clave new
y asignaremos algunos valores.
Si imprimimos más información sobre nuestro nuevo objeto con console.log(hero1)
, podemos apreciar más detalles sobre lo que sucede con la inicialización de clase.
OutputHero {name: "Varg", level: 1}
__proto__:
▶ constructor: class Hero
▶ greet: ƒ greet()
Podemos ver en el resultado que las funciones constructor()
y greet()
se aplicaron a __proto__
, o [[Prototype]]
de hero1
, y no directamente como método en el objeto hero1
. Aunque esto queda de manifiesto en la creación de funciones de constructor, no resulta evidente al crear clases. Las clases permiten una sintaxis más sencilla y sucinta, aunque sacrifican algo de claridad en el proceso.
Una característica ventajosa de las funciones y clases constructoras es que pueden ampliarse a nuevos esquemas de objeto basados en el elemento principal. Esto impide la repetición de código para objetos similares, pero necesitan características adicionales o más específicas.
Se pueden crear nuevas funciones constructoras desde el elemento principal usando el método call()
. En el siguiente ejemplo, crearemos una clase de carácter más específica llamada Mage
y le asignaremos las propiedades de Hero
usando call()
, además de agregar una propiedad.
En este punto, podemos crear una nueva instancia de Mage
usando las mismas propiedades de Hero
, así como también una nueva que agregamos.
Al enviar hero2
a la consola, podemos apreciar que creamos una nueva clase Mage
basada en la constructora.
OutputMage {name: "Lejon", level: 2, spell: "Magic Missile"}
__proto__:
▶ constructor: ƒ Mage(name, level, spell)
Con clases de ES6, la palabra clave super
se usa en lugar de call
para acceder a las funciones principales. Usaremos extends
para hacer referencia a la clase principal.
Ahora podemos crear una nueva instancia de Mage
de la misma manera.
Imprimiremos hero2
en la consola y veremos el resultado.
OutputMage {name: "Lejon", level: 2, spell: "Magic Missile"}
__proto__: Hero
▶ constructor: class Mage
El resultado es casi exactamente el mismo, con la diferencia de que en la construcción de clase [[Prototype]]
se vincula al elemento principal; en este caso, Hero
.
A continuación, se muestra una comparación en paralelo de todo el proceso de inicialización, incorporación de métodos y herencia de una función constructor y una clase.
Aunque la sintaxis es bastante distinta, el resultado subyacente es casi el mismo para ambos métodos. Las clases nos ofrecen una alternativa más concisa para crear esquemas de objeto y las funciones constructor describen con mayor precisión lo que sucede en segundo plano.
En este tutorial, incorporó conocimientos sobre las similitudes y diferencias entre las funciones constructor de JavaScript y las clases de ES6. Tanto las clases como las funciones constructor imitan un modelo de herencia orientado hacia objetos para JavaScript, que es un lenguaje de herencia basado en prototipos.
Comprender la herencia prototípica es primordial para desempeñarse con eficacia como desarrollador de JavaScript. Familiarizarse con las clases es extremadamente útil, ya que en las bibliotecas de JavaScript populares como React se usa con frecuencia la sintaxis class
.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!