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:
- chocando con otras aplicaciones / bibliotecas
- Alcance contaminante superior (globalmente más probable)
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)
o Self Executing Anonymous Function
.
Código explicado
var someFunction = function(){ console.log('wagwan!'); };
(function() { /* function scope starts here */
console.log('start of IIFE');
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})(); /* function scope ends */
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
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:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
};
myMainFunction(); // I CALL "myMainFunction" FUNCTION HERE
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
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:
var italianSayinSomething = function(){ console.log('mamamia!'); }();
Entonces nuestro ejemplo más complejo se convierte en:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
}();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
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:
function(){ console.log('mamamia!'); }();
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:
(function(){ console.log('mamamia!'); })(); // live demo: jsbin.com/zokuwodoco/1/edit?js,console.
o
+function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wuwipiyazi/1/edit?js,console
o
-function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wejupaheva/1/edit?js,console
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"
var someFunction = function(){ console.log('wagwan!'); };
(function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
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?"
(function() {
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
myOtherFunction = function(){ /* oops, an assignment instead of a declaration */
console.log('haha. got ya!');
};
})();
myOtherFunction(); // reachable, hence works: see in the console
window.myOtherFunction(); // works in the browser, myOtherFunction is then in the global scope
myFunction(); // unreachable, will throw an error, see in the console
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 hacer window.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:
- javascript no tiene
block scope
(Actualización: variables locales de alcance de bloque agregadas en ES6 ).
- javascript solo tiene
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 lo module pattern
que comúnmente se hace aprovechando este patrón IIFE. Que te diviertas :)