¿Alguien puede aclarar la diferencia entre una función de constructor y una función de fábrica en Javascript.
¿Cuándo usar uno en lugar del otro?
fuente
¿Alguien puede aclarar la diferencia entre una función de constructor y una función de fábrica en Javascript.
¿Cuándo usar uno en lugar del otro?
La diferencia básica es que se usa una función de constructor con la new
palabra clave (lo que hace que JavaScript cree automáticamente un nuevo objeto, se establezca this
dentro de la función en ese objeto y devuelva el objeto):
var objFromConstructor = new ConstructorFunction();
Una función de fábrica se llama como una función "regular":
var objFromFactory = factoryFunction();
Pero para que se considere una "fábrica" necesitaría devolver una nueva instancia de algún objeto: no lo llamaría una función de "fábrica" si solo devuelve un valor booleano o algo así. Esto no sucede automáticamente como con new
, pero permite más flexibilidad en algunos casos.
En un ejemplo realmente simple, las funciones a las que se hace referencia anteriormente podrían verse así:
function ConstructorFunction() {
this.someProp1 = "1";
this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };
function factoryFunction() {
var obj = {
someProp1 : "1",
someProp2 : "2",
someMethod: function() { /* whatever */ }
};
// other code to manipulate obj in some way here
return obj;
}
Por supuesto, puede hacer que las funciones de fábrica sean mucho más complicadas que ese simple ejemplo.
Una ventaja de las funciones de fábrica es cuando el objeto a devolver podría ser de varios tipos diferentes, dependiendo de algún parámetro.
someMethod
los objetos devueltos por la fábrica, y ahí es donde se pone un poco nublado. Dentro de la función de fábrica, si uno solo lo hacevar obj = { ... , someMethod: function() {}, ... }
, eso llevaría a que cada objeto devuelto mantenga una copia diferente de lasomeMethod
cual es algo que podríamos no querer. Ahí es donde usarnew
yprototype
dentro de la función de fábrica ayudaría.new
con la función de constructor; Pensé que es donde uno podría necesitar ver un ejemplo de cómo reemplazar constructores con funciones de fábrica y ahí es donde pensé que se requería la coherencia en los ejemplos. De todos modos, la respuesta es suficientemente informativa. Este era solo un punto que quería plantear, no es que esté reduciendo la calidad de la respuesta de ninguna manera.new
internamente oObject.create()
para crear un objeto con un prototipo específico.Beneficios de usar constructores
La mayoría de los libros te enseñan a usar constructores y
new
this
se refiere al nuevo objetoA algunas personas les gusta la forma de
var myFoo = new Foo();
leer.Inconvenientes
Los detalles de la instanciación se filtran en la API de llamada (a través del
new
requisito), por lo que todas las personas que llaman están estrechamente vinculadas a la implementación del constructor. Si alguna vez necesita la flexibilidad adicional de la fábrica, tendrá que refactorizar a todas las personas que llaman (ciertamente, el caso excepcional, en lugar de la regla).Olvidar
new
es un error tan común, debe considerar agregar una verificación repetitiva para asegurarse de que el constructor se llame correctamente (if (!(this instanceof Foo)) { return new Foo() }
). EDITAR: desde ES6 (ES2015) no se puede olvidarnew
con unclass
constructor, o el constructor arrojará un error.Si realiza la
instanceof
verificación, deja ambigüedad en cuanto a sinew
se requiere o no . En mi opinión, no debería ser así. Efectivamente ha cortocircuitado elnew
requisito, lo que significa que podría borrar el inconveniente # 1. Pero entonces tienes una función de fábrica en todo menos en nombre , con repetitivo adicional, una letra mayúscula y unthis
contexto menos flexible .Los constructores rompen el principio abierto / cerrado
Pero mi principal preocupación es que viola el principio abierto / cerrado. Comienza exportando un constructor, los usuarios comienzan a usar el constructor, luego, en el futuro, se da cuenta de que necesita la flexibilidad de una fábrica, en su lugar (por ejemplo, para cambiar la implementación para usar grupos de objetos, o para crear instancias en contextos de ejecución, o para tener más flexibilidad de herencia usando prototipado OO).
Sin embargo, estás atrapado. No puede realizar el cambio sin romper todo el código que llama a su constructor
new
. No puede cambiar a usar agrupaciones de objetos para aumentar el rendimiento, por ejemplo.Además, el uso de constructores le da un engaño
instanceof
que no funciona en contextos de ejecución, y no funciona si su prototipo de constructor se intercambia. También fallará si comienza a regresarthis
de su constructor, y luego cambia a exportar un objeto arbitrario, lo que tendría que hacer para habilitar un comportamiento de fábrica en su constructor.Beneficios de usar fábricas
Menos código: no se requiere repetitivo.
Puede devolver cualquier objeto arbitrario y usar cualquier prototipo arbitrario, lo que le brinda más flexibilidad para crear varios tipos de objetos que implementan la misma API. Por ejemplo, un reproductor multimedia que puede crear instancias de HTML5 y reproductores flash, o una biblioteca de eventos que puede emitir eventos DOM o eventos de socket web. Las fábricas también pueden crear instancias de objetos en contextos de ejecución, aprovechar las agrupaciones de objetos y permitir modelos de herencia de prototipos más flexibles.
Nunca necesitaría convertir de una fábrica a un constructor, por lo que la refactorización nunca será un problema.
No hay ambigüedad sobre el uso
new
. No lo hagas (Hará que sethis
comporte mal, vea el siguiente punto).this
se comporta como lo haría normalmente, por lo que puede usarlo para acceder al objeto primario (por ejemplo, en el interiorplayer.create()
, sethis
refiereplayer
, como cualquier otra invocación de método,call
yapply
también reasignarthis
, como se esperaba. Si almacena prototipos en el objeto primario, eso puede ser una excelente manera de intercambiar dinámicamente la funcionalidad y permitir un polimorfismo muy flexible para la creación de instancias de su objeto.No hay ambigüedad sobre si capitalizar o no. No lo hagas Las herramientas de pelusa se quejarán, y luego sentirás la tentación de intentar usarlas
new
, y luego deshacerás el beneficio descrito anteriormente.A algunas personas les gusta el camino
var myFoo = foo();
o lasvar myFoo = foo.create();
lecturas.Inconvenientes
new
no se comporta como se esperaba (ver arriba). Solución: no lo use.this
no se refiere al nuevo objeto (en cambio, si el constructor se invoca con notación de punto o notación de corchetes, por ejemplo, foo.bar () - sethis
refiere afoo
, al igual que cualquier otro método de JavaScript, vea los beneficios).fuente
new
viola el principio abierto / cerrado. Visite medium.com/javascript-scene/… para una discusión mucho más amplia que la que permiten estos comentarios.new
palabra clave, no creo que lanew
palabra clave realmente proporcione ninguna legibilidad adicional. En mi opinión, parece una tontería saltar a través de los aros para permitir a las personas que llaman escribir más.Un constructor devuelve una instancia de la clase a la que la llama. Una función de fábrica puede devolver cualquier cosa. Usaría una función de fábrica cuando necesite devolver valores arbitrarios o cuando una clase tenga un proceso de configuración grande.
fuente
Un ejemplo de función de constructor
new
crea un objeto prototipoUser.prototype
y llamaUser
con el objeto creado como suthis
valor.new
trata una expresión de argumento para su operando como opcional:causaría
new
llamarUser
sin argumentos.new
devuelve el objeto que creó, a menos que el constructor devuelva un valor de objeto , que se devuelve en su lugar. Este es un caso extremo que en su mayor parte puede ignorarse.Pros y contras
Los objetos creados por las funciones de constructor heredan propiedades de la propiedad del constructor
prototype
y devuelven verdadero usando elinstanceOf
operador en la función de constructor.Los comportamientos anteriores pueden fallar si cambia dinámicamente el valor de la
prototype
propiedad del constructor después de haber usado el constructor. Hacerlo es raro , y no se puede cambiar si el constructor se creó con laclass
palabra clave.Las funciones de constructor se pueden ampliar utilizando la
extends
palabra clave.Las funciones del constructor no pueden regresar
null
como un valor de error. Como no es un tipo de datos de objeto, es ignorado pornew
.Un ejemplo de función de fábrica
Aquí la función de fábrica se llama sin
new
. La función es totalmente responsable del uso directo o indirecto si sus argumentos y el tipo de objeto que devuelve. En este ejemplo, devuelve un [Objeto objeto] simple con algunas propiedades establecidas a partir de argumentos.Pros y contras
Oculta fácilmente las complejidades de implementación de la creación de objetos de la persona que llama. Esto es particularmente útil para las funciones de código nativo en un navegador.
La función de fábrica no siempre necesita devolver objetos del mismo tipo, e incluso podría regresar
null
como un indicador de error.En casos simples, las funciones de fábrica pueden ser simples en estructura y significado.
Los objetos devueltos generalmente no heredan de la
prototype
propiedad de la función de fábrica y regresanfalse
deinstanceOf factoryFunction
.La función de fábrica no se puede extender de forma segura utilizando la
extends
palabra clave porque los objetos extendidos heredarían de laprototype
propiedad de funciones de fábrica en lugar de laprototype
propiedad del constructor utilizado por la función de fábrica.fuente
Las fábricas son "siempre" mejores. Cuando se usan lenguajes orientados a objetos, entonces
Las implementaciones (los objetos reales creados con nuevos) no están expuestos al usuario / consumidor de fábrica. Esto significa que el desarrollador de la fábrica puede expandirse y crear nuevas implementaciones siempre que no rompa el contrato ... y permite que el consumidor de la fábrica se beneficie de la nueva API sin tener que cambiar su código ... si usaron una nueva y aparece una "nueva" implementación, entonces tienen que ir y cambiar cada línea que usa "nueva" para usar la "nueva" implementación ... con la fábrica, su código no cambia ...
Fábricas, mejor que cualquier otra cosa, el marco de resorte está completamente construido alrededor de esta idea.
fuente
Las fábricas son una capa de abstracción y, como todas las abstracciones, tienen un costo complejo. Al encontrar una API basada en la fábrica, descubrir cuál es la fábrica para una API determinada puede ser un desafío para el consumidor de API. Con los constructores, la capacidad de descubrimiento es trivial.
Al decidir entre fábricas y fábricas, debe decidir si la complejidad está justificada por el beneficio.
Vale la pena señalar que los constructores de Javascript pueden ser fábricas arbitrarias al devolver algo diferente a esto o indefinido. Por lo tanto, en js puede obtener lo mejor de ambos mundos: API reconocible y agrupación / almacenamiento en caché de objetos.
fuente
new
, Alterar el comportamiento dethis
, Alterar el valor de retorno, Conectar un prototipo de referencia, Habilitarinstanceof
(que yace y no debe usarse para este propósito). Aparentemente, todas esas son "características". En la práctica, dañan la calidad de su código.Por las diferencias, Eric Elliott aclaró muy bien:
Pero para la segunda pregunta:
Si viene del fondo orientado a objetos, la función Constructor le parece más natural. de esta manera no debes olvidarte de usar
new
palabras clave.fuente