ejemplos - ¿Cómo se llama este patrón de JavaScript y por qué se usa?
javascript html (6)
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, vea el método de Raycast here ).
La variación normal de tal método se vería así:
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 de ejecución automática.
- 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 conjetura sobre por qué se usa esto es que limita el número de instancias para la barra (solo habrá una) y, por lo tanto, ahorra sobrecarga de administración de memoria.
Mis preguntas:
- ¿Es correcta esta suposición?
- ¿Hay un nombre para este patrón?
- ¿Por qué se usa esto?
En el ejemplo proporcionado, el primer fragmento utilizará la misma instancia de tmpObject para cada llamada a la función foo (), donde, como en el segundo fragmento, tmpObject será una nueva instancia cada vez.
Una razón por la que se pudo haber usado el primer fragmento es que la variable tmpObject se puede compartir entre llamadas a foo (), sin que su valor se filtre en el ámbito en el que se declara foo ().
La versión de la función no ejecutada inmediatamente del primer fragmento en realidad se vería así:
var tmpObject = new Bar();
function foo(){
// Use tmpObject.
}
Sin embargo, tenga en cuenta que esta versión tiene tmpObject en el mismo ámbito que foo (), por lo que podría manipularse más adelante.
Una mejor manera de lograr la misma funcionalidad sería usar un módulo separado:
Módulo ''foo.js'':
var tmpObject = new Bar();
module.exports = function foo(){
// Use tmpObject.
};
Módulo 2:
var foo = require(''./foo'');
Una comparación entre el rendimiento de un IEF y una función de creador foo con nombre: http://jsperf.com/ief-vs-named-function
La diferencia clave entre su código y el código Three.js es que en el código Three.js la variable
tmpObject
solo se inicializa una vez y luego se comparte por cada invocación de la función devuelta.
Esto sería útil para mantener cierto estado entre llamadas, similar a cómo se usan las variables
static
en lenguajes tipo C.
tmpObject
es una variable privada solo visible para la función interna.
Cambia el uso de la memoria, pero no está diseñado para ahorrar memoria.
Limita los costos de inicialización del objeto y además garantiza que todas las invocaciones de funciones usen el mismo objeto. Esto permite, por ejemplo, que el estado se almacene en el objeto para futuras invocaciones.
Si bien es posible que limite el uso de memoria, por lo general, el GC recolectará objetos no utilizados de todos modos, por lo que es probable que este patrón no ayude mucho.
Este patrón es una forma específica de closure .
Me gustaría contribuir a este interesante hilo extendiéndome al concepto del patrón de módulo revelador, que garantiza que todos los métodos y variables se mantengan privados hasta que estén expuestos explícitamente.
En el último caso, el método de suma se llamaría como Calculator.add ();
No estoy seguro de si este patrón tiene un nombre más correcto, pero esto 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) asegura 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
.
Sus suposiciones son casi correctas. Repasemos esos primero.
- Asigna el retorno de una función autoejecutable
Esto se llama una 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 palabra clave
private
o 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 .
¿Hay un nombre para este patrón?
AFAIK puede llamar a este patrón Módulo Patrón . Citando:
El patrón Módulo encapsula "privacidad", estado y organización mediante cierres. Proporciona una forma de envolver una mezcla de métodos y variables públicas y privadas, evitando que las piezas se filtren en el ámbito global y colisionen accidentalmente con la interfaz de otro desarrollador. Con este patrón, solo se devuelve una API pública, manteniendo todo lo demás dentro del cierre privado.
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 utilizando el primer ejemplo. Una coincidencia estrecha con este punto puede ser los métodos estáticos de fábrica como se describe en Effective Java.
- Es efficient si necesita el mismo estado de objeto cada vez.
Pero si solo necesita el objeto vainilla cada vez, entonces este patrón probablemente no agregará ningún valor.