¿Qué son las funciones de fábrica y los constructores?

0 acciones
0
0
0
0

Introducción

Para comprender el concepto de funciones de fábrica y constructores, primero debe comprender las funciones y los objetos.

Si creas muchos objetos con propiedades y funciones similares, puede resultar aburrido y repetitivo. Debemos tener presente el principio del código DRY, que significa "No te repitas". Existen patrones funcionales que pueden ayudarnos a escribir código más corto, limpio y eficiente. Las funciones de fábrica y las funciones constructoras pueden funcionar, pero ¿cuál deberías usar? Profundicemos un poco más en qué son las funciones de fábrica y los constructores, qué pueden y no pueden hacer, y sus similitudes y diferencias.

¿Qué es la función de fábrica?

Una función de fábrica puede considerarse como una fábrica real que recibe materias primas y produce múltiples productos rápidamente. En cambio, las funciones de fábrica reciben entradas específicas y las utilizan para crear un nuevo objeto. Entonces, ¿cómo puede esto sernos útil? Podríamos simplemente crear cada objeto individualmente, pero podría llevar tiempo. Si se crean objetos con las mismas propiedades y diferentes valores, crear una función de fábrica puede acelerar el proceso.

const car1 = {
make: 'Toyota',
model: 'Tacoma',
year: 2018,
fuelType: 'gas', 
bodyType: 'mid-size pick-up truck',
getFullName() {
return `${this.year} ${this.make} ${this.model}`;
}
}
console.log(car1.getFullName()); // => 2018 Toyota Tacoma

En el ejemplo anterior, creamos un objeto que describe una máquina específica. Ahora, creemos un objeto similar a este.

const car2 = {
make: 'Tesla', 
model: 'Model S',
year: 2018,
fuelType: 'electric',
bodyType: 'sedan',
getFullName() {
return `${this.year} ${this.make} ${this.model}`;
}
}
console.log(car2.getFullName()); // => 2018 Tesla Model S 

Podría seguir hablando de crear más objetos de máquina, pero ¿quién tiene tiempo para eso? Veamos cómo funciona esto como función de fábrica.

function createCar (make, model, year, fuelType, bodyType) {
return {
make: make, 
model: model, 
year: year, 
fuelType: fuelType, 
bodyType: bodyType,
getFullName() {
return `${year} ${make} ${model}`;
}
}
}

Ahora tenemos una función de fábrica que crea nuevos objetos. Solo necesitamos pasar los datos y dejar que la función de fábrica haga su trabajo.

function createCar (make, model, year, fuelType, bodyType) {
return {
make: make, 
model: model, 
year: year, 
fuelType: fuelType, 
bodyType: bodyType,
getFullName() {
return `${year} ${make} ${model}`;
}
}
}
const car1 = createCar('Toyota', 'Tacoma', 2018, 'gas', 'mid-size pick-up truck');
const car2 = createCar('Tesla', 'Model S', 2018, 'electric', 'sedan');
console.log(car1.getFullName()); // => 2018 Toyota Tacoma
console.log(car2.getFullName()); // => 2018 Tesla Model S

Puede crear cualquier cantidad de objetos utilizando una función de fábrica en lugar de repetir código.

¿Qué son los constructores?

La función constructora es otro patrón de JavaScript muy similar a las funciones de fábrica. Sin embargo, a diferencia de las funciones de fábrica, las funciones constructoras no devuelven un objeto. Para crear objetos diferentes con las mismas propiedades, necesitamos usar las palabras clave "new" y "this". Dicho esto, veamos cómo funcionan visualmente las funciones constructoras.

function Car(make, model, year, fuelType, bodyType) {
this.make = make
this.model = model 
this.year = year
this.fuelType = fuelType
this.bodyType = bodyType
this.getFullName = () => {
return `${this.year} ${this.make} ${this.model}`;
}
}

En el ejemplo anterior, la función constructora es muy similar a una función de fábrica, salvo por el uso de la palabra clave "this". "this" se refiere a la función constructora que creó el objeto de instancia. En otras palabras, "this" no tiene valor en una función constructora. Se puede considerar como la base para el nuevo objeto.

function Car(make, model, year, fuelType, bodyType) {
this.make = make
this.model = model 
this.year = year
this.fuelType = fuelType
this.bodyType = bodyType
this.getFullName = () => {
return `${this.year} ${this.make} ${this.model}`;
}
}
const car1 = new car('Toyota', 'Tacoma', 2018, 'gas', 'mid-size pick-up truck');
const car2 = new car('Tesla', 'Model S', 2018, 'electric', 'sedan');
console.log(car1.getFullName()); // => 2018 Toyota Tacoma
console.log(car2.getFullName()); // => 2018 Tesla Model S

Para crear objetos mediante funciones constructoras, usamos otra palabra clave llamada "new". Al usar la instrucción "new" antes de una llamada a una función, JavaScript realiza dos acciones automáticamente: dentro de la función, crea un objeto vacío llamado "this" y devuelve el objeto "this" a la instrucción que originalmente llamó a la función.

function Car(make, model, year, fuelType, bodyType) {
// const this = {};
this.make = make
this.model = model 
this.year = year
this.fuelType = fuelType
this.bodyType = bodyType
this.getFullName = () => {
return `${this.year} ${this.make} ${this.model}`;
}
// return this;
}
const car1 = new car('Toyota', 'Tacoma', 2018, 'gas', 'mid-size pick-up truck');
const car2 = new car('Tesla', 'Model S', 2018, 'electric', 'sedan');
console.log(car1.getFullName()); // => 2018 Toyota Tacoma
console.log(car2.getFullName()); // => 2018 Tesla Model S

Herencia

La herencia juega un papel importante en la diferencia entre las funciones de fábrica y de constructor.

function createCar (make, model, year, fuelType, bodyType) {
return {
make: make, 
model: model, 
year: year, 
fuelType: fuelType, 
bodyType: bodyType,
getFullName() {
return `${year} ${make} ${model}`;
}
}
}
const car1 = createCar('Toyota', 'Tacoma', 2018, 'gas', 'mid-size pick-up truck');
const car2 = createCar('Tesla', 'Model S', 2018, 'electric', 'sedan'); 
car1.getFullName = function() {
return `My ${fuelType} ${bodyType} is a ${year} ${make} ${model}`;
}
console.log(car1.getFullName()); // => My gas mid-size pick-up truck is a 2018 Toyota Tacoma
console.log(car2.getFullName()); // => 2018 Tesla Model S

Volvamos al primer ejemplo de una función de fábrica. ¿Qué sucede si queremos volver a declarar car1.getFullName()? Pues bien, car1.getFullName() y car2.getFullName() no son la misma función en memoria. Cada objeto obtiene su propia copia de la función. Esto significa que cuando la función crea un objeto y lo devuelve, copia las propiedades y los valores, y los vincula a cada objeto que la llama.

function car(make, model, year, fuelType, bodyType) {
// const this = {};
this.make = make
this.model = model 
this.year = year
this.fuelType = fuelType
this.bodyType = bodyType
this.getFullName = () => {
return `${this.year} ${this.make} ${this.model}`;
}
// return this;
}
const car1 = new car('Toyota', 'Tacoma', 2018, 'gas', 'mid-size pick-up truck');
const car2 = new car('Tesla', 'Model S', 2018, 'electric', 'sedan');
console.log(car1); // => car {make: 'Toyota', model: 'Tacoma' , etc.}

Ahora veamos nuestra función constructora anterior. Al crearse, el constructor tiene su propio prototipo. Al crear un nuevo objeto Car con la palabra clave "new", se crea una instancia del tipo Car. En otras palabras, el prototipo de car1 es del tipo Car. Ahora car1 hereda del constructor Car. Esto nos permite añadir propiedades al prototipo Car.

Car.prototype.sentence = function() {
return `My ${this.fuelType} ${this.bodyType} is a ${this.year} ${this.make} ${this.model}`;
}
console.log(car1); // => Car {
// make: 'Toyota',
// model: 'Tacoma',
// year: 2018,
// fuelType: 'gas',
// bodyType: 'mid-size pick-up truck',
// getFullName: [Function (anonymous)]
// }

Tenga en cuenta que la función de oración no se agrega directamente al generador de automóviles.

console.log(Car.prototype); // => { sentence: [Function (anonymous)] }

Pero al revisar su prototipo, ¡ahí está! Ahora podemos acceder a la función recién añadida.

console.log(car1.sentence()); // => My gas mid-size pick-up truck is a 2018 Toyota Tacoma
console.log(car2.sentence()); // => My electric sedan is a 2018 Tesla Model S

Ahora que conocemos el funcionamiento de cada operación, la pregunta es: ¿cuál deberíamos usar? Ambas pueden dar el mismo resultado. Los constructores son excelentes para agregar o eliminar una propiedad de cualquier objeto que herede del constructor. Sin embargo, las funciones de fábrica son más fáciles de entender porque, al fin y al cabo, son simplemente funciones. Para las funciones de fábrica, no necesitamos introducir la palabra clave "new". Gracias a las clausuras, pueden ser más flexibles. Con ellas, podemos lograr algo llamado "privacidad de datos". Veamos otro ejemplo que explica cómo funciona esto.

function createCar(make, model, year) {
return {
getFullName() {
return `${year} ${make} ${model}`;
}
}
}
const car1 = createCar('Toyota', 'Tacoma', 2018); 
console.log(car1.getFullName()); // => 2018 Toyota Tacoma
console.log(car1.make); // => undefined
console.log(car1); // => { getFullName: [Function: getFullName] }

Resultado

En general, lo importante de escribir tu propio código es que no tiene nada de malo. Hay una buena manera de mantenerlo limpio y breve: usa funciones de fábrica y constructoras cuando lo consideres más adecuado.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

También te puede gustar