javascript - ¿Hay alguna razón para definir module.exports usando un IIFE?
node.js (2)
Mi equipo no tiene desarrolladores de JS con experiencia, pero estamos escribiendo una biblioteca en Node y recibimos una sugerencia de un desarrollador de JS real que dice: "Debemos hacer que el js sea más modular, no para contaminar el espacio de nombres global y hacerlo más legible". a los recién llegados ", y nos dijo que hiciéramos lo siguiente:
module.exports = (function(){
return {
nameToExpose: functionToExpose
...
};
})();
más bien que
module.exports.nameToExpose = functionToExpose;
¿Cuál es el punto de esto, en su caso? Este último no hace ninguna declaración local que sería objeto de alcance por el IIFE, e incluso si lo hiciera, serían locales para el archivo del módulo y no globales para todo el programa que lo require()
.
Algunas búsquedas en Google sobre este sitio no dan respuesta a esta pregunta en particular, aunque hay muchas otras explicaciones de las IIFE que he leído (y que se resumen en el comentario anterior). Algunas pruebas ciertamente revelan que este último no pone realmente functionToExpose
en el espacio de nombres global, aunque su nombre original se registra en el tipo de función en sí.
Casi ninguna diferencia La idea general de Node.js, usar require
, tener módulos, etc., es específicamente para separar las preocupaciones. Diría (con cautela) que si lo haces bien, no deberías preocuparte por "contaminar" ningún tipo de alcance global. Cualquier cosa dentro de module.exports
vive en ese módulo.
Cuando se trata de cosas de front-end, es cuando el alcance global se convierte en una cuestión de preocupación, porque si una función o lo que sea no está dentro del alcance (es decir, en un IIFE u otro bloque de función), tiene acceso al objeto de window
global, y todo lo demás tiene acceso a esa función.
un verdadero desarrollador de JS
Llamar a alguien que es una bandera roja.
no contaminar el espacio de nombres global y hacerlo más legible para los recién llegados
Si está modularizando su código correctamente, eso no debería ser una preocupación. Hay un momento y un lugar para las IIFE, pero no veo ninguna razón por la cual envolver todo en un IIFE, que ya se encuentra dentro de un módulo , de alguna manera mágicamente haría que el código sea "más modular" o que sea más legible para los "nuevos usuarios" que por simplemente usando Node.js como fue diseñado:
module.exports = function() { ... } // whatever
e incluso si lo hiciera, serían locales para el archivo del módulo y no globales para todo el programa que lo
require()
.
Estás en lo correcto. Tomaría todo lo que dice con un grano de sal. Tal vez sepa de algunos casos de uso específicos en los que su enfoque le haya sido útil en el pasado, así que le pregunto específicamente sobre eso para ver qué dice. Aparte de eso, siento que estás en el camino correcto.
La razón por la que a veces puede hacer esto es porque si no lo hace, entonces todas las variables que necesite para el objeto module.exports
deben tener un alcance para todo el archivo.
Considera estas dos maneras.
Sin IIFE.
var foo = ''la'' + ''la''; // some computed value // // ... lots of program code here ... // module.exports = { foo : foo, };
Con IIFE.
// // ... lots of program code here ... // module.exports = (function () { var foo = ''la'' + ''la''; // some computed value return { foo : foo } }());
En el primer ejemplo, surgen dos problemas.
- Sus variables (como
foo
) se crean bastante lejos de donde se utilizan para exportar un valor desde el módulo. Esto puede reducir la claridad. Claro, puede declarar una variable después del código del programa, pero aún tiene el mismo alcance (y lasvar
son hoisted ). Además, la mejor práctica general es declarar todas sus variables por adelantado, y no hacerlo es una compensación a considerar. - El código del programa puede alterar sus variables, intencional o accidentalmente, lo que complica las cosas y es indeseable a menos que lo necesite (a veces lo hace).
El segundo ejemplo elimina estos problemas al tener un ámbito privado para esa área del archivo. Aún puede usar variables que están dentro del alcance de todo el archivo, pero en los casos en que no lo necesita, puede tener variables que sean más fáciles de leer y comprender.
Muchas veces programamos para humanos, no máquinas. Este es un ejemplo de optimización para el primero.
Actualizar:
En las versiones modernas de JavaScript, const y let son probablemente mejores soluciones a los problemas que este patrón pretende resolver. Con ellos, puede definir variables de una manera que arrojará errores si comete los mismos errores de los que IIFE está tratando de protegerlo.
//
// ... lots of program code here ...
//
const foo = ''la'' + ''la''; // some computed value
module.exports = {
foo : foo,
};
En el ejemplo anterior, si el código del programa usa foo
, se bloqueará con un ReferenceError
, debido a la Zona Muerta Temporal , en lugar de recibir undefined
como lo haría una var
. Esto es genial porque ahora debe mover explícitamente la declaración de foo
a un lugar anterior en el código si su uso fue intencional, o de lo contrario corregir el código.