Últimamente he estado leyendo mucho Javascript y me he dado cuenta de que todo el archivo está envuelto de la siguiente manera en los archivos .js que se van a importar.
(function() {
...
code
...
})();
¿Cuál es la razón para hacer esto en lugar de un simple conjunto de funciones de constructor?
javascript
scope
coding-style
iife
Andrew Kou
fuente
fuente
Respuestas:
Suele ser espacio de nombres (ver más adelante) y controlar la visibilidad de las funciones y / o variables de los miembros. Piense en ello como una definición de objeto. El nombre técnico para ello es una expresión de función invocada inmediatamente (IIFE). Los complementos de jQuery generalmente se escriben así.
En Javascript, puede anidar funciones. Entonces, lo siguiente es legal:
Ahora puede llamar
outerFunction()
, pero la visibilidad deinnerFunction()
está limitada al alcance deouterFunction()
, lo que significa que es privadoouterFunction()
. Básicamente sigue el mismo principio que las variables en Javascript:Correspondientemente:
En el escenario anterior, puede llamar
globalFunction()
desde cualquier lugar, pero no puede llamarlocalFunction1
olocalFunction2
.Lo que estás haciendo cuando escribes
(function() { ... })()
es convertir el código dentro del primer conjunto de paréntesis en una función literal (lo que significa que todo el "objeto" es en realidad una función). Después de eso, está invocando la función (la final()
) que acaba de definir. Entonces, la principal ventaja de esto, como mencioné antes, es que puede tener métodos / funciones y propiedades privadas:En el primer ejemplo, invocaría explícitamente
globalFunction
por nombre para ejecutarlo. Es decir, lo haríaglobalFunction()
para ejecutarlo. Pero en el ejemplo anterior, no solo estás definiendo una función; lo estás definiendo e invocando de una vez. Esto significa que cuando se carga el archivo JavaScript, se ejecuta inmediatamente. Por supuesto, podrías hacer:El comportamiento sería en gran medida el mismo, excepto por una diferencia significativa: evita contaminar el alcance global cuando usa un IIFE (como consecuencia, también significa que no puede invocar la función varias veces ya que no tiene un nombre, pero dado que esta función solo debe ejecutarse una vez que realmente no sea un problema).
Lo bueno de IIFE es que también puede definir cosas dentro y solo exponer las partes que desea al mundo exterior (un ejemplo de espacio de nombres para que pueda crear su propia biblioteca / complemento):
¡Ahora puede llamar
myPlugin.public_function1()
, pero no puede accederprivate_function()
! Muy parecido a una definición de clase. Para entender esto mejor, recomiendo los siguientes enlaces para leer más:EDITAR
Olvidé mencionarlo. En esa final
()
, puedes pasar todo lo que quieras dentro. Por ejemplo, cuando crea complementos jQuery, pasajQuery
o le$
gusta:Entonces, lo que está haciendo aquí es definir una función que tome en un parámetro (llamada
jQ
, una variable local, y conocida solo por esa función). Luego, está invocando la función y pasando un parámetro (también llamadojQuery
, pero este es del mundo exterior y una referencia al jQuery real). No hay una necesidad apremiante de hacer esto, pero hay algunas ventajas:Anteriormente describí cómo estas funciones se ejecutan automáticamente al inicio, pero si se ejecutan automáticamente, ¿quién pasa los argumentos? Esta técnica supone que todos los parámetros que necesita ya están definidos como variables globales. Entonces, si jQuery no estaba definido como una variable global, este ejemplo no funcionaría. Como puede suponer, una cosa que jquery.js hace durante su inicialización es definir una variable global 'jQuery', así como su variable global más famosa '$', que permite que este código funcione después de que se haya incluido jQuery.
fuente
;(function(jQ) { ... code ... })(jQuery);
esta manera, si alguien dejara un punto y coma en su secuencia de comandos, no rompería la suya, especialmente si planea minificar y concatenar su secuencia de comandos con otra.(function (context) { ..... })(this)
que luego le permite adjuntar todo lo que desee al contexto principal, exponiéndolo.En breve
Resumen
En su forma más simple, esta técnica tiene como objetivo envolver el código dentro del alcance de una función .
Ayuda a disminuir las posibilidades de:
Que no se detecta cuando el documento esté listo - no es una especie de
document.onload
niwindow.onload
Es comúnmente conocido como un
Immediately Invoked Function Expression (IIFE)
oSelf Executing Anonymous Function
.Código explicado
En el ejemplo anterior, cualquier variable definida en la función (es decir, declarada usando
var
) será "privada" y accesible dentro del alcance de la función SOLAMENTE (como lo expresa Vivin Paliath). En otras palabras, estas variables no son visibles / accesibles fuera de la función. Ver demostración en vivo .Javascript tiene función de alcance. "Los parámetros y las variables definidas en una función no son visibles fuera de la función, y que una variable definida en cualquier lugar dentro de una función es visible en todas partes dentro de la función". (de "Javascript: las partes buenas").
Más detalles
Código alternativo
Al final, el código publicado antes también podría hacerse de la siguiente manera:
Ver demostración en vivo .
Las raices
Iteración 1
Un día, alguien probablemente pensó "debe haber una manera de evitar nombrar 'myMainFunction', ya que todo lo que queremos es ejecutarlo de inmediato".
Si vuelve a lo básico, descubre que:
expression
: algo evaluando a un valor. es decir3+11/x
statement
: línea (s) de código que hace algo PERO no evalúa a un valor. es decirif(){}
Del mismo modo, las expresiones de función evalúan a un valor. Y una consecuencia (¿supongo?) Es que se pueden invocar de inmediato:
Entonces nuestro ejemplo más complejo se convierte en:
Ver demostración en vivo .
Iteración 2
El siguiente paso es el pensamiento "¿por qué
var myMainFunction =
si ni siquiera lo usamos?".La respuesta es simple: intente eliminar esto, como a continuación:
Ver demostración en vivo .
No funcionará porque "las declaraciones de funciones no son invocables" .
El truco es que al eliminar
var myMainFunction =
transformamos la expresión de la función en una declaración de función . Consulte los enlaces en "Recursos" para obtener más detalles al respecto.La siguiente pregunta es "¿por qué no puedo mantenerlo como una expresión de función con otra cosa que no sea
var myMainFunction =
?La respuesta es "usted puede", y en realidad hay muchas maneras en que podría hacer esto: agregando a
+
, a!
, a-
, o tal vez envolviendo un par de paréntesis (como ahora se hace por convención), y creo que hay más. Como ejemplo:o
o
Entonces, una vez que se agrega la modificación relevante a lo que alguna vez fue nuestro "Código Alternativo", volvemos al mismo código exacto que el utilizado en el ejemplo de "Código Explicado"
Leer más sobre
Expressions vs Statements
:Alcance desmitificador
Una cosa que uno podría preguntarse es "¿qué sucede cuando NO define la variable 'correctamente' dentro de la función, es decir, hace una asignación simple en su lugar?"
Ver demostración en vivo .
Básicamente, si se asigna un valor a una variable que no se declaró en su alcance actual, entonces "se produce una búsqueda en la cadena del alcance hasta que encuentra la variable o alcanza el alcance global (en ese momento la creará)".
Cuando se encuentra en un entorno de navegador (frente a un entorno de servidor como nodejs), el
window
objeto define el alcance global . Por lo tanto podemos hacerwindow.myOtherFunction()
.Mi consejo de "Buenas prácticas" sobre este tema es usar siempre
var
al definir cualquier cosa : ya sea un número, un objeto o una función, e incluso en el ámbito global. Esto hace que el código sea mucho más simple.Nota:
block scope
(Actualización: variables locales de alcance de bloque agregadas en ES6 ).function scope
&global scope
(window
alcance en un entorno de navegador)Leer más sobre
Javascript Scopes
:Recursos
Próximos pasos
Una vez que obtiene este
IIFE
concepto, lo lleva a lomodule pattern
que comúnmente se hace aprovechando este patrón IIFE. Que te diviertas :)fuente
Javascript en un navegador solo tiene un par de alcances efectivos: alcance de la función y alcance global.
Si una variable no está en el alcance de la función, está en el alcance global. Y las variables globales son generalmente malas, por lo que esta es una construcción para mantener las variables de una biblioteca para sí mismo.
fuente
Eso se llama un cierre. Básicamente sella el código dentro de la función para que otras bibliotecas no interfieran con él. Es similar a crear un espacio de nombres en idiomas compilados.
Ejemplo. Supongamos que escribo:
Ahora otras bibliotecas no pueden acceder a la variable
x
que creé para usar en mi biblioteca.fuente
(function(){ ... return { publicProp1: 'blah' }; })();
. Obviamente no es perfectamente paralelo al espacio de nombres, pero puede ser útil pensarlo de esa manera.También puede usar cierres de funciones como datos en expresiones más grandes, como en este método para determinar el soporte del navegador para algunos de los objetos html5.
fuente
Además de mantener las variables locales, un uso muy útil es cuando se escribe una biblioteca usando una variable global, puede darle un nombre de variable más corto para usar dentro de la biblioteca. A menudo se usa para escribir complementos de jQuery, ya que jQuery le permite deshabilitar la variable $ que apunta a jQuery, usando jQuery.noConflict (). En caso de que esté deshabilitado, su código aún puede usar $ y no romperse si solo lo hace:
fuente
fuente
También debemos usar 'use estricto' en la función de alcance para asegurarnos de que el código se ejecute en "modo estricto". Código de muestra que se muestra a continuación
fuente