¿Cómo se llama este patrón de JavaScript y por qué se utiliza?
Estoy estudiando THREE.js y noté un patrón donde las funciones se definen así:
var foo = ( function () {
var bar = new Bar();
return function ( ) {
//actual logic using bar from above.
//return result;
};
}());
(Ejemplo, consulte el método raycast aquí ).
La variación normal de dicho método sería la siguiente:
var foo = function () {
var bar = new Bar();
//actual logic.
//return result;
};
Comparando la primera versión con la variación normal , la primera parece diferir en eso:
- Asigna el resultado de una función autoejecutable.
- Define una variable local dentro de esta función.
- Devuelve la función real que contiene la lógica que hace uso de la variable local.
Entonces, la principal diferencia es que en la primera variación la barra solo se asigna una vez, en la inicialización, mientras que la segunda variación crea esta variable temporal cada vez que se llama.
Mi mejor suposición sobre por qué se usa esto es que limita el número de instancias de bar (solo habrá una) y, por lo tanto, ahorra gastos generales de administración de memoria.
Mis preguntas:
- ¿Es correcta esta suposición?
- ¿Existe un nombre para este patrón?
- ¿Por qué se usa esto?
Tus suposiciones son casi correctas. Repasemos esos primero.
- Asigna el retorno de una función autoejecutable.
Esto se llama expresión de función invocada inmediatamente o IIFE.
- Define una variable local dentro de esta función.
Esta es la forma de tener campos de objetos privados en JavaScript, ya que de lo contrario no proporciona la private
palabra clave ni la funcionalidad.
- Devuelve la función real que contiene la lógica que hace uso de la variable local.
Nuevamente, el punto principal es que esta variable local es privada .
¿Existe un nombre para este patrón?
AFAIK, puedes llamar a este patrón Patrón de módulo . Citando:
El patrón Módulo encapsula "privacidad", estado y organización mediante cierres. Proporciona una forma de envolver una combinación de métodos y variables públicos y privados, protegiendo las piezas para que no se filtren al alcance global y choquen accidentalmente con la interfaz de otro desarrollador. Con este patrón, solo se devuelve una API pública, manteniendo privado todo lo demás dentro del cierre.
Comparando esos dos ejemplos, mis mejores conjeturas sobre por qué se usa el primero son:
- Está implementando el patrón de diseño Singleton.
- Se puede controlar la forma en que se puede crear un objeto de un tipo específico usando el primer ejemplo. Una coincidencia cercana con este punto pueden ser los métodos de fábrica estáticos como se describe en Java efectivo.
- Es eficiente si necesita el mismo estado del objeto cada vez.
Pero si solo necesita el objeto básico cada vez, entonces este patrón probablemente no agregará ningún valor.
Limita los costos de inicialización del objeto y, además, garantiza que todas las invocaciones de funciones utilicen el mismo objeto. Esto permite, por ejemplo, almacenar el estado en el objeto para que lo utilicen futuras invocaciones.
Si bien es posible que limite el uso de la memoria, normalmente el GC recolectará objetos no utilizados de todos modos, por lo que este patrón probablemente no ayude mucho.
Este patrón es una forma específica de cierre .
No estoy seguro de si este patrón tiene un nombre más correcto, pero me parece un módulo y la razón por la que se usa es para encapsular y mantener el estado.
El cierre (identificado por una función dentro de una función) garantiza que la función interna tenga acceso a las variables dentro de la función externa.
En el ejemplo que dio, la función interna se devuelve (y se asigna a foo
) ejecutando la función externa, lo que significa que tmpObject
continúa viviendo dentro del cierre y múltiples llamadas a la función interna foo()
operarán en la misma instancia de tmpObject
.