clases o funciones
Para poder definir clases tenemos básicamente dos opciones, utilizar class
o utilizar function
. Aunque puedan parecer muy diferentes, son completamente equivalentes, como vamos ir viendo en toda esta serie de artículos.
class | function |
class C {} console.assert( typeof C === 'function' ); | function C () {} console.assert( typeof C === 'function' ); |
En ambos casos, el tipo es function
. Esto puede sorprender un poco, ya que quizás se podría esperar que class
fuera de otro tipo, quizás uno específico, pero ambos son funciones, funciones constructoras, es decir, que se espera que se utilicen con new
.
Si analizamos estas funciones obtendremos esta información sobre la cadena de prototipos del constructor:
prototipo
Las funciones (y por lo tanto, también las clases) tienen una propiedad denominada prototype
donde reside la información que es utilizada para crear los objetos. Todos los miembros del objeto prototype
del constructor serán miembros del objeto una vez instanciado con new
:
class | function |
class C { m1() { } m2() { } } const obj = new C(); console.assert( typeof obj.m1 === 'function' ); console.assert( typeof obj.m2 === 'function' ); | function C () { } C.prototype = { m1: function() { }, m2: function() { } }; const obj = new C(); console.assert( typeof obj.m1 === 'function' ); console.assert( typeof obj.m2 === 'function' ); |
Si exploramos el objeto obj
y el prototipo C.prototype
comprobaremos que ambos tiene los mismos miembros:
Es interesante saber que si modificamos dinámicamente el prototipo de una clase, estamos cambiando todos los objetos creados a partir de ella, ya los miembros de C.prototype
no se copian, si no que se hacen referencia al mismo dentro de obj.__proto__
(más adelante veremos que es y cómo funciona esta extraña propiedad llamada __proto__
.
hoisting
class | function |
try { const obj = new C(); console.assert( false ); } catch (err) { console.assert( err.message === 'C is not defined' ); } class C { } | const obj = new C(); function C () { } |
Las funciones pueden ser llamadas en el código antes de su definición, esto es así por medio del proceso de hoisting que se produce en la compilación del Javascript.
Esto no ocurre con las clases, que deben ser siempre declaradas en el código antes de su uso. Debemos tenerlo en cuenta para evitar errores.
alcance
class | function |
{ class C { } } try { const obj = new C(); console.assert( false ); } catch (err) { console.assert( err.message === 'C is not defined' ); } | function x () { function C () { } } try { const obj = new C(); console.assert( false ); } catch (err) { console.assert( err.message === 'C is not defined' ); } |
Como la mayoría de los elementos definidos en Javascript, estos tiene un alcance o ámbito definido. class
tiene el alcance comprendido por llaves, de forma similar a las variables creadas con let
. Por su parte function
es local la función donde ha sido definida. No podemos, por lo tanto, utilizar una clase o una función constructora fuera del alcance donde se encuentra.
expresión anónima
class | function |
const C = class {}; console.assert( typeof C === 'function' ); | const C = function () {}; console.assert( typeof C === 'function' ); |
Tanto las funciones como las clases pueden ser utilizadas como expresiones y, por lo tanto, pueden ser definidas de forma anónima, es decir, sin aplicarles un nombre concreto. Las clases y las funciones pueden almacenarse en variables, pasarse como parámetros o retornarse desde funciones. Son, por lo tanto, miembros de primer orden del lenguaje.
Si una clase o una función es asignada a una variable o pasada como parámetro, no se produce una copia de la misma, como todos los objetos de Javascript (recordemos que Function
hereda de Object
) es pasado por referencia y se mantiene una sola instancia referenciada por varias variables.
Índice | constructor |