¿Cuál es el propósito de una función de ejecución automática en javascript?


427

En javascript, ¿cuándo quieres usar esto?

(function(){
    //Bunch of code...
})();

Más allá de esto:

//Bunch of code...

3
También eche un vistazo a una explicación ( técnica ) y aquí . Para la sintaxis, vea por qué los paréntesis son necesarios y hacia dónde deben ir .
Bergi


¿Por qué tiene los dos últimos paréntesis, justo antes del punto y coma?
Johnny

3
@johnny la parte anterior a esos dos últimos paréntesis declara una función (anónima). Esos dos paréntesis llaman a la función.
Ej.

77
"Expresión de función invocada inmediatamente" o IIFE es un mejor nombre para esto.
Flimm

Respuestas:


404

Se trata de alcance variable. Las variables declaradas en la función de ejecución automática están, por defecto, solo disponibles para codificar dentro de la función de ejecución automática. Esto permite que el código se escriba sin preocuparse de cómo se nombran las variables en otros bloques de código JavaScript.

Por ejemplo, como se menciona en un comentario de Alexander :

(function() {
  var foo = 3;
  console.log(foo);
})();

console.log(foo);

Esto primero registrará 3y luego arrojará un error en el siguiente console.logporque foono está definido.


77
Y también para el beneficio de muchas personas, incluidos un montón de ingenieros de Netflix: ES SOLO UNA FUNCIÓN. No es en sí mismo representativo de un cierre. A veces, los invocadores automáticos se usan junto con escenarios relevantes para el cierre para hacer cosas ordenadas, pero si no ve algo que se aferre a una referencia que se recolectaría como basura y desaparecería en un lenguaje sin cierre, no tiene nada que ver volviendo loco con CIERRES.
Erik Reppen

2
Entonces, esto significa, ¿se usa principalmente con cierre?
Pir Abdul

@AlexanderBird, no del todo bien ... si no lo haces var, así ...function(){ foo=3;}:? Establecería una variable global, ¿verdad?
T.Todua

2
@AlexanderBird, pero eso ya sucede en las variables locales dentro de las funciones: function(){ var foo = 3; alert(foo); }; alert(foo);así que todavía no lo entiendo
João Pimentel Ferreira

Ah, lo entiendo, logras todas estas 3 características a la vez: 1) ejecutas la función solo declarándola; 2) Como cualquier función, el alcance de las variables es solo local; y 3) La función puede ser anónima, sin contaminar el alcance principal
João Pimentel Ferreira

94

Simplista. Muy normal, es casi reconfortante:

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

Sin embargo, ¿qué sucede si incluyo una biblioteca de JavaScript realmente útil en mi página que traduce los caracteres avanzados en sus representaciones de nivel base?

¿Esperar lo?

Quiero decir, si alguien teclea un personaje con algún tipo de acento, pero solo quiero caracteres 'ingleses' AZ en mi programa. Bueno ... los caracteres españoles 'ñ' y franceses 'é' pueden traducirse en caracteres base de 'n' y 'e'.

Entonces, una persona agradable ha escrito un conversor de caracteres completo que puedo incluir en mi sitio ... Lo incluyo.

Un problema: tiene una función llamada 'nombre' igual que mi función.

Esto es lo que se llama colisión. Tenemos dos funciones declaradas en el mismo alcance con el mismo nombre. Queremos evitar esto.

Por lo tanto, necesitamos analizar nuestro código de alguna manera.

La única forma de abarcar el código en javascript es envolverlo en una función:

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

Eso podría resolver nuestro problema. Ahora todo está cerrado y solo se puede acceder desde nuestras llaves de apertura y cierre.

Tenemos una función en una función ... que es extraño de ver, pero totalmente legal.

Solo un problema. Nuestro código no funciona. ¡Nuestra variable userName nunca se repite en la consola!

Podemos resolver este problema agregando una llamada a nuestra función después de nuestro bloque de código existente ...

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

main();

¡O antes!

main();

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

Una preocupación secundaria: ¿cuáles son las posibilidades de que el nombre 'main' aún no se haya utilizado? ... muy, muy delgado.

Necesitamos más alcance. Y alguna forma de ejecutar automáticamente nuestra función main ().

Ahora llegamos a las funciones de ejecución automática (o autoejecutable, autoejecutable, lo que sea).

((){})();

La sintaxis es incómoda como el pecado. Sin embargo, funciona.

Cuando ajusta una definición de función entre paréntesis e incluye una lista de parámetros (¡otro conjunto o paréntesis!), Actúa como una llamada de función .

Así que echemos un vistazo a nuestro código nuevamente, con alguna sintaxis autoejecutable:

(function main() {
  var userName = "Sean";

    console.log(name());

    function name() {
      return userName;
    }
  }
)();

Entonces, en la mayoría de los tutoriales que lees, ahora serás bombardeado con el término 'autoejecutable anónimo' o algo similar.

Después de muchos años de desarrollo profesional, le recomiendo encarecidamente que nombre todas las funciones que escriba con fines de depuración.

Cuando algo sale mal (y lo hará), verificará la traza inversa en su navegador. Siempre es más fácil reducir los problemas de código cuando las entradas en el seguimiento de la pila tienen nombres!

Enormemente largo aliento y espero que ayude!


2
Gracias :) Estuve buscando en Internet todo el tiempo tratando de comprender las ventajas de IIFE en relación con las funciones normales en términos de privacidad variable y su respuesta es simplemente la mejor. Todo el mundo dice que una de las mejores ventajas es que las variables y funciones dentro de IIFE son 'finalmente' privadas cuando una función normal simplemente te da exactamente lo mismo. Finalmente creo que lo conseguí a través de su proceso de explicación. IIFE es solo una función, pero ahora entiendo por qué usarlo. ¡Gracias de nuevo!
viery365

Gracias por tomarse el tiempo de explicar esto tan bien.
MSC

Buena respuesta. Sin embargo, tengo una pregunta sobre su último punto: cuando recomienda que se nombren todas las funciones, ¿está diciendo que hay una manera de hacerlo con funciones autoejecutables, o sugiere que todos nombren la función y luego la llamen? EDITAR Oh, ya veo. Este ya está nombrado. Duh Es posible que desee señalar que está justificando su uso de una función autoejecutable con nombre.
FireSBurnsmuP

Bueno mi amigo, esta es LA respuesta que estaba buscando:)
João Pimentel Ferreira

Esta es la respuesta que estaba buscando, no la que está marcada como aceptada. ¿Estoy en lo cierto al decir que no se trata de la colisión de nombres de variables , sino de la colisión de nombres de funciones ? Las variables, incluso en funciones normales que no son de vida, tienen un alcance local y no colisionan con variables globales, ¿no es así?
Kumar Manish

32

La autoinvocación (también conocida como autoinvocación) es cuando una función se ejecuta inmediatamente después de su definición. Este es un patrón central y sirve como base para muchos otros patrones de desarrollo de JavaScript.

Soy un gran fan :) porque:

  • Mantiene el código al mínimo
  • Impone la separación del comportamiento de la presentación.
  • Proporciona un cierre que evita conflictos de nombres

Enormemente - (¿Por qué deberías decir que es bueno?)

  • Se trata de definir y ejecutar una función de una vez.
  • Podría hacer que esa función de ejecución automática devuelva un valor y pase la función como parámetro a otra función.
  • Es bueno para la encapsulación.
  • También es bueno para el alcance de bloque.
  • Sí, puede incluir todos sus archivos .js en una función de ejecución automática y puede evitar la contaminación del espacio de nombres global. ;)

Más aquí .


43
Punto 1. ¿Cómo? Punto 2. Eso es de una mejor práctica completamente diferente. Punto 3. ¿Qué función no tiene? 4,5,6,7. ¿Relevancia? 8. Bueno, 1/8 no está mal, supongo.
Erik Reppen

2
Siete años de retraso pero, para el punto 1. no reduce el código en absoluto, de hecho, agrega un mínimo de dos líneas de código al crear la función.
YungGun

1
El único punto aquí es "Proporciona un cierre que evita conflictos de nombres", cada otro punto es una nueva redacción de esto o falso. tal vez puedas simplificar tu respuesta?
pcarvalho

19

Espaciado de nombres. Los ámbitos de JavaScript son de nivel de función.


77
todavía se reciben votos negativos porque utilicé el espacio de nombres en lugar del alcance ; esto es una cuestión de definición; consulte, por ejemplo, Wikipedia : un espacio de nombres en ciencias de la computación (a veces también denominado ámbito de nombre), es un contenedor o entorno abstracto creado para contener una agrupación lógica de identificadores o símbolos únicos (es decir, nombres). y Un identificador de espacio de nombres puede proporcionar contexto (Alcance en ciencias de la computación) a un nombre, y los términos a veces se usan indistintamente.
Christoph

55
Los ámbitos de nivel de función de Javascript proporcionan el espacio en el que viven los nombres de variables, un espacio de nombres ; que es anónimo y no está asociado con un identificador de espacio de nombres es irrelevante ...
Christoph

12

No puedo creer que ninguna de las respuestas mencione globales implícitos.

El (function(){})()constructo no protege contra los globales implícitos, lo que para mí es la mayor preocupación, consulte http://yuiblog.com/blog/2006/06/01/global-domination/

Básicamente, el bloque de función se asegura de que todos los "variables globales" dependientes que definió estén confinados en su programa, no lo protege contra la definición de globales implícitos. JSHint o similares pueden proporcionar recomendaciones sobre cómo defenderse contra este comportamiento.

La var App = {}sintaxis más concisa proporciona un nivel de protección similar y puede incluirse en el bloque de funciones cuando se encuentra en páginas "públicas". (vea Ember.js o SproutCore para ejemplos del mundo real de bibliotecas que usan esta construcción)

En cuanto a las privatepropiedades, están sobrevaloradas a menos que esté creando un marco público o biblioteca, pero si necesita implementarlas, Douglas Crockford tiene algunas buenas ideas.


8
El modo estricto protege contra globales implícitos. Eso, junto con un invocador automático, lo cubriría. Nunca entendí el alboroto sobre las propiedades privadas. Declara vars dentro de un constructor func. Hecho. Si la idea de olvidarse de usar la palabra clave 'nuevo' lo mantiene despierto por la noche, escriba una función de fábrica. Hecho de nuevo
Erik Reppen

8

He leído todas las respuestas, aquí falta algo muy importante , BESO. Hay 2 razones principales por las que necesito funciones anónimas autoejecutables, o mejor dicho " Expresión de función invocada de inmediato (IIFE) ":

  1. Mejor gestión del espacio de nombres (Evitar la contaminación del espacio de nombres -> Módulo JS)
  2. Cierres (Simulación de miembros de clase privada, como se conoce de OOP)

El primero se ha explicado muy bien. Para el segundo, estudie el siguiente ejemplo:

var MyClosureObject = (function (){
  var MyName = 'Michael Jackson RIP';
  return {
    getMyName: function () { return MyName;},
    setMyName: function (name) { MyName = name}
  }
}());

Atención 1: no estamos asignando una función a MyClosureObject, más aún el resultado de invocar esa función . Tenga en cuenta ()en la última línea.

Atención 2: lo que además debe saber sobre las funciones en Javascript es que las funciones internas tienen acceso a los parámetros y variables de las funciones, que están definidas dentro.

Probemos algunos experimentos:

Puedo MyNameusar getMyNamey funciona:

 console.log(MyClosureObject.getMyName()); 
 // Michael Jackson RIP

El siguiente enfoque ingenuo no funcionaría:

console.log(MyClosureObject.MyName); 
// undefined

Pero puedo establecer otro nombre y obtener el resultado esperado:

MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName()); 
// George Michael RIP

Editar: en el ejemplo anterior MyClosureObjectestá diseñado para usarse sin el newprefijo, por lo tanto, por convención, no debe escribirse en mayúscula.


7

¿Hay un parámetro y el "Bunch of code" devuelve una función?

var a = function(x) { return function() { document.write(x); } }(something);

Cierre. El valor de somethingse usa por la función asignada a a. somethingpodría tener algún valor variable (para bucle) y cada vez que a tiene una nueva función.


+1; Yo prefiero una explícita var x = something;en el exterior sobre la función xcomo parámetro, sin embargo: imo que es más fácil de leer de esta manera ...
Christoph

@Christoph: si el valor de "algo" cambia después de que se crea la función, utilizará el nuevo valor y no el que está en el momento de su creación.
stesch

@stesch: ¿de dónde sacaste eso? Que yo sepa, ese no es el caso; la única forma de obtener referencias reales en JS es mediante el uso de argumentos-objeto, pero incluso eso no funciona en todos los navegadores
Christoph

@Christoph: "JavaScript: The Good Parts", Douglas Crockford (O'Reilly)
stesch

@stesch: no funciona de la manera que lo describe: el nuevo valor se usará si elimina la variable xy depende directamente del alcance léxico, es decir document.write(something)...
Christoph

6

Alcance de aislamiento, tal vez. Para que las variables dentro de la declaración de función no contaminen el espacio de nombres externo.

Por supuesto, en la mitad de las implementaciones de JS que existen, de todos modos lo harán.


44
¿Qué implementaciones serían esas?
Matthew Crumley

1
Cualquier implementación que no esté escrita en modo estricto y que contenga una declaración var implícita que haga que sea global.
Erik Reppen

5

Aquí hay un ejemplo sólido de cómo una función anónima autoinvocatoria podría ser útil.

for( var i = 0; i < 10; i++ ) {
  setTimeout(function(){
    console.log(i)
  })
}

Salida: 10, 10, 10, 10, 10...

for( var i = 0; i < 10; i++ ) {
  (function(num){
    setTimeout(function(){
      console.log(num)
    })
  })(i)
}

Salida: 0, 1, 2, 3, 4...


Puede explicar un poco más sobre lo que está sucediendo para el primer conjunto de código
radio_head

En letlugar del varprimer caso estará bien.
Vitaly Zdanevich

3

Una diferencia es que las variables que declaras en la función son locales, por lo que desaparecen cuando sales de la función y no entran en conflicto con otras variables en otro código.


1

Dado que las funciones en Javascript son objetos de primera clase, al definirlo de esa manera, define efectivamente una "clase" muy parecida a C ++ o C #.

Esa función puede definir variables locales y tener funciones dentro de ella. Las funciones internas (métodos de instancia efectivos) tendrán acceso a las variables locales (variables de instancia efectivas), pero estarán aisladas del resto del script.


1

Función auto invocada en javascript:

Una expresión autoinvocatoria se invoca (inicia) automáticamente, sin ser llamada. Una expresión autoinvocatoria se invoca justo después de su creación. Esto se usa básicamente para evitar conflictos de nombres y para lograr la encapsulación. Las variables u objetos declarados no son accesibles fuera de esta función. Para evitar los problemas de minimización (filename.min) use siempre la función autoejecutada.


1

Las funciones de ejecución automática se utilizan para administrar el alcance de una variable.

El alcance de una variable es la región de su programa en la que se define.

Una variable global tiene alcance global; se define en todas partes en su código JavaScript y se puede acceder desde cualquier lugar dentro del script, incluso en sus funciones. Por otro lado, las variables declaradas dentro de una función se definen solo dentro del cuerpo de la función. Son variables locales, tienen alcance local y solo se puede acceder dentro de esa función. Los parámetros de la función también cuentan como variables locales y se definen solo dentro del cuerpo de la función.

Como se muestra a continuación, puede acceder a la variable variable global dentro de su función y también observar que dentro del cuerpo de una función, una variable local tiene prioridad sobre una variable global con el mismo nombre.

var globalvar = "globalvar"; // this var can be accessed anywhere within the script

function scope() {
    alert(globalvar);
    localvar = "localvar" //can only be accessed within the function scope
}

scope(); 

Entonces, básicamente, una función de ejecución automática permite que el código se escriba sin preocuparse de cómo se nombran las variables en otros bloques de código javascript.


1
(function(){
    var foo = {
        name: 'bob'
    };
    console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error

En realidad, la función anterior se tratará como expresión de función sin un nombre.

El objetivo principal de ajustar una función con paréntesis abiertos y cerrados es evitar contaminar el espacio global.

Las variables y funciones dentro de la expresión de la función se volvieron privadas (es decir) no estarán disponibles fuera de la función.


1

La respuesta corta es: para prevenir la contaminación del alcance global (o superior).

IIFE (Expresiones de funciones invocadas inmediatamente) es la mejor práctica para escribir scripts como complementos, complementos, scripts de usuario o cualquier script que se espere que funcione con los scripts de otras personas . Esto garantiza que cualquier variable que defina no produzca efectos no deseados en otros scripts.

Esta es la otra forma de escribir la expresión IIFE. Personalmente prefiero este siguiente método:

void function() {
  console.log('boo!');
  // expected output: "boo!"
}();

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void

Según el ejemplo anterior, está muy claro que IIFE también puede afectar la eficiencia y el rendimiento, porque la función que se espera que se ejecute solo una vez se ejecutará una vez y luego se descargará en el vacío para siempre . Esto significa que la declaración de función o método no permanece en la memoria.


Agradable, no había visto ese uso de voidantes. Me gusta.
Ej.

1

Primero debes visitar MDN IIFE , ahora algunos puntos sobre esto

  • esta es la expresión de función invocada inmediatamente . Entonces, cuando su archivo javascript se invoca desde HTML, esta función se llama de inmediato.
  • Esto evita el acceso a variables dentro del lenguaje IIFE, además de contaminar el alcance global.

0

Parece que esta pregunta ha sido respondida lista, pero de todos modos publicaré mi opinión.

Sé cuándo me gusta usar funciones de ejecución automática.

var myObject = {
    childObject: new function(){
        // bunch of code
    },
    objVar1: <value>,
    objVar2: <value>
}

La función me permite usar un código adicional para definir los atributos y propiedades de childObjects para un código más limpio, como establecer variables de uso común o ejecutar ecuaciones matemáticas; Oh! o comprobación de errores. en lugar de limitarse a la sintaxis de instanciación de objetos anidados de ...

object: {
    childObject: {
        childObject: {<value>, <value>, <value>}
    }, 
    objVar1: <value>,
    objVar2: <value>
}

La codificación en general tiene muchas formas oscuras de hacer muchas de las mismas cosas, haciendo que te preguntes, "¿Por qué molestarse?" Pero siguen apareciendo nuevas situaciones en las que ya no puede confiar solo en los principios básicos / básicos.


0

Dada su simple pregunta: "En javascript, ¿cuándo desea utilizar esto: ..."

Me gustan las respuestas de @ken_browning y @ sean_holding, pero aquí hay otro caso de uso que no veo mencionado:

let red_tree = new Node(10);

(async function () {
    for (let i = 0; i < 1000; i++) {
        await red_tree.insert(i);
    }
})();

console.log('----->red_tree.printInOrder():', red_tree.printInOrder());

donde Node.insert es una acción asincrónica.

No puedo simplemente llamar en espera sin la palabra clave asíncrona en la declaración de mi función, y no necesito una función con nombre para su uso posterior, pero necesito esperar esa llamada de inserción o necesito otras características más completas (¿quién sabe?) .


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.