1. El patrón Constructor
JavaScript no nació con paradigmas de orientación a objetos puros, pero permite simular clases mediante funciones constructoras. En este enfoque, se utiliza la palabra clave this para asignar propiedades al contexto del nuevo objeto.
function Felino() {
this.alias = "Michi";
}
var mascota1 = new Felino();
console.log(mascota1.alias); // Michi
Los métodos pueden vincularse al prototipo de la función para optimizar la memoria, evitando duplicar la lógica en cada instancia.
Felino.prototype.emitirSonido = function() {
console.log("Miau");
};
2. El método Object.create()
Introducido en ECMAScript 5, este mecanismo permite crear instancias directamente a partir de un objeto prototípico, sin necesidad de utiliazr new ni lidiar con la complejidad de this en la declaración inicial.
var Felino = {
alias: "Michi",
emitirSonido: function() { console.log("Miau"); }
};
var mascota1 = Object.create(Felino);
console.log(mascota1.alias); // Michi
mascota1.emitirSonido(); // Miau
Para entornos antigous que carecen de soporte nativo, se puede implementar un polyfill sencillo:
if (typeof Object.create !== 'function') {
Object.create = function(proto) {
function ConstructorIntermedio() {}
ConstructorIntermedio.prototype = proto;
return new ConstructorIntermedio();
};
}
3. El enfoque de Fábrica Minimalista
Esta técnica evita por completo el uso de this y prototype, utilizando un objeto simple que contiene una función generadora. Al invocarla, se construye y retorna un nuevo objeto con sus propiedades y métodos.
var Felino = {
generar: function() {
var instancia = {};
instancia.alias = "Michi";
instancia.emitirSonido = function() { console.log("Miau"); };
return instancia;
}
};
var mascota1 = Felino.generar();
mascota1.emitirSonido(); // Miau
Herencia
Para que una clase herede de otra, basta con invocar el método generador de la clase base dentro del generador de la subclase.
var SerVivo = {
generar: function() {
var instancia = {};
instancia.reposar = function() { console.log("Durmiendo"); };
return instancia;
}
};
var Felino = {
generar: function() {
var instancia = SerVivo.generar();
instancia.alias = "Michi";
instancia.emitirSonido = function() { console.log("Miau"); };
return instancia;
}
};
var mascota1 = Felino.generar();
mascota1.reposar(); // Durmiendo
Privacidad de variables
Las variables declaraads dentro del bloque de la función generadora, pero no adjuntadas al objeto de retorno, permanecen privadas gracias al cierre (closure) de la función.
var Felino = {
generar: function() {
var instancia = {};
var secreto = "Miau";
instancia.revelarSecreto = function() { console.log(secreto); };
return instancia;
}
};
var mascota1 = Felino.generar();
console.log(mascota1.secreto); // undefined
Datos compartidos
Si se necesita que todas las instancias accedan o modifiquen un mismo estado, este dato debe declararse en el objeto contenedor principal, fuera de la función generadora.
var Felino = {
sonidoCompartido: "Miau",
generar: function() {
var instancia = {};
instancia.escuchar = function() { console.log(Felino.sonidoCompartido); };
instancia.actualizarSonido = function(nuevo) { Felino.sonidoCompartido = nuevo; };
return instancia;
}
};
var mascota1 = Felino.generar();
var mascota2 = Felino.generar();
mascota2.actualizarSonido("Prrr");
mascota1.escuchar(); // Prrr