¿qué es?
En JavaScript, cada función, cuando se llama, crea un nuevo contexto de ejecución. Debido a que las variables y las funciones definidas en las funciones son las únicas variables a las que se accede internamente, no externamente, al llamar a una función, el contexto proporcionado por la función proporciona una forma muy simple de crear variables privadas.
función makecounter () {var i = 0; function de return () {console.log (++ i); }; } // Recuerde: `contar` y` contar2` tienen sus propias variables `i`var contar = makeCounter (); contar (); // 1counter (); // 2var contar2 = makeCounter (); contar2 (); // 1counter2 (); // 2i; // referenciar: no está definido (solo existe en makecunter)En muchos casos, es posible que no necesite una función como hacer lo que sea para devolver múltiples valores acumulados, y solo puede llamarla una vez para obtener un solo valor, y en algunos otros casos ni siquiera necesita saber el valor de retorno explícitamente.
Su núcleo
Ahora, no importa, defina una función como la función foo () {} o var foo = function () {}, al llamar, debe agregar un par de paréntesis después de él, como foo ().
// La función definida a continuación se puede llamar agregando un par de entre pardos después del nombre de la función, como `foo ()`, // porque foo es solo una variable de referencia var foo = function () {/ * code */} `relativa a la expresión de la función` function () {/ * código */} `var foo = function () {/ */ */} // // luego muestra que la función de la función puede ser un par corchetes después de eso? function () { / * código * /} (); // SyntaxError: Token inesperado (Como puede ver, se atrapa un error aquí. Cuando los paréntesis aparecen detrás de una función para llamar a una función, ya sea que encuentre dicha palabra clave de la función en el entorno global o el entorno local, por defecto, lo tratará como una declaración de función en lugar de una expresión de función. Si no le dice explícitamente a los paréntesis que es una expresión, lo tratará como una función sin un nombre y arrojará un error, porque la declaración de función requiere un nombre.
Pregunta 1: ¿Puedo pensar en una pregunta aquí? ¿Podemos también llamar a la función var foo = function () {console.log (1)} () directamente así, y la respuesta está bien?
Pregunta 2: Del mismo modo, también podemos pensar en una pregunta. Si una declaración de función como esta se llama directamente con los paréntesis después de ella, ¿qué sucede? Consulte la respuesta a continuación.
Función, paréntesis, error
Curiosamente, si especifica un nombre para una función y coloca un par de paréntesis detrás, se lanzará el mismo error, pero esta vez es por otra razón. Cuando se colocan paréntesis después de una expresión de la función, indica que esta es una función llamada, y los paréntesis se colocan después de una declaración, significa que están completamente separados de la declaración de función anterior. En este momento, los paréntesis son solo una representación simple de un paréntesis (aparatos utilizados para controlar la prioridad de operación).
// Sin embargo, la declaración de la función es sintácticamente inválida, sigue siendo una declaración y los siguientes paréntesis no son válidos, porque los paréntesis deben incluir la función de expresión foo () {/* código*/} (); // sintaxError: token inexipible // ahora, usted pone una expresión en los parentivos sin lanzar un error ..., pero la función no es ejecutada, porque no se ejecuta, porque no se ejecuta, porque no se ejecuta () porque no se ejecuta () porque la función no es ejecutada (). Código */} (1) // Es equivalente a lo siguiente, una declaración de función sigue una expresión que no tiene ninguna relación: function foo () {/ *código */} (1);Ejecutar expresiones de funciones inmediatamente (iife)
Afortunadamente, es fácil corregir errores de gramática. El método más popular y más aceptado es envolver las declaraciones de funciones entre paréntesis para decirle al analizador que exprese una expresión de función, porque en Javascript, las paréntesis no pueden contener declaraciones. Debido a esto, cuando las paréntesis encuentran la palabra clave de la función para envolver la función, sabe analizarla como una expresión de función en lugar de una declaración de función. Preste atención a la comprensión de que los paréntesis aquí son diferentes de los paréntesis anteriores cuando encuentran funciones, es decir, es, es decir,
Cuando aparecen paréntesis al final de una función anónima y desean llamar a una función, predeterminará tratar la función como una declaración de función.
Al envolver una función entre paréntesis, analizará la función como una expresión por defecto, en lugar de declarar la función.
// Ambos patrones se pueden usar para llamar a una expresión de función de inmediato, utilizando la ejecución de la función para crear variables privadas (function () {/ * código */} ()); // Crockford recomienda esta, la expresión en los soportes representa la función inmediatamente (function () {/ * código */}) (); // pero esta funciona tan bien en los soportes en la función de la función /// Los operadores son desambiguar // entre expresiones de funciones y declaraciones de funciones, pueden ser // omitirse cuando el analizador ya espera una expresión (pero consulte // "Nota importante" a continuación) .var i = function () {return 10;} (); true && function () {/*code*/} (); 0, function () {} (); // no le importa el valor de retorno, o haga su código, oa el código de requisito, o haga que el código sea reítate como el código de retorno. ¡Posible, puede almacenar bytes tomando un operador unario frente a su función! function () {/ * code */} (); ~ function () {/ * code */} (); - function () {/ * code */} ();+function () {/ * code */} (); // Aquí hay otra variación, de @kuvos, no estoy seguro de la actuación // implicaciones, si de cualquier otra, de usar la `nueva y la palabra clave, pero es una palabra clave. http://twitter.com/kuvos/status/18209252090847232new function () {/ * code */} nueva función () {/ * code */} () // solo necesita parenes si pasa argumentosNotas importantes sobre los soportes
En algunos casos, no es necesario rodear la expresión de la función cuando los soportes ambiguos adicionales están alrededor de la expresión de la función (porque los soportes ya se expresan como una expresión), pero esto sigue siendo una buena idea cuando los soportes se usan para llamar a la expresión de la función.
Tales paréntesis indican que la expresión de la función se llamará de inmediato y que la variable almacenará el resultado de la función, no la función misma. Cuando se trata de una expresión de la función muy larga, esto ahorra tiempo que las personas que leen su código sin tener que desplazarse al final de la página para ver si se llama a la función.
Como regla general, cuando escribe un código claro y claro, es necesario evitar que JavaScript arroje errores, ¡y también es necesario evitar que otros desarrolladores le arrojen errores a usted.
Guardar el estado del cierre
Al igual que cuando se llama a una función por su nombre, se pasan los parámetros y cuando la expresión de la función se llama inmediatamente, se pasan los parámetros. Se puede usar una expresión de función inmediatamente llamada para bloquear los valores y guardar efectivamente el estado en este momento, porque cualquier función definida dentro de una función puede usar parámetros y variables pasadas por la función exterior (esta relación se llama cierre).
// Puede que no funcione como piensas, porque el valor de `i` nunca está bloqueado. // Por el contrario, cuando se hace clic en cada enlace (el bucle se ha ejecutado bien), por lo tanto, aparecerá el número total de todos los elementos, // porque este es el verdadero valor de `I` en este momento. var elems = document.getElementsByTagName ('a'); for (var i = 0; i <elems.length; i ++) {elems [i] .adDeventListener ('click', function (e) {e.preventDefault (); alerta ('i iAnl #'+ i)}, falso);} // y rewrite, es más abajo, está bien, si está bien. El valor de `I` está bloqueado en 'LockedInIndex'. // Cuando se ejecuta el bucle, aunque el valor numérico del valor `I` es la suma de todos los elementos, cada vez que se llama la expresión de la función, el valor 'LockedInindex` en iife es el valor que se le pasó' I`, por lo que cuando se hace clic en el enlace, el valor correcto se produce. var elems = document.getElementsByTagName ('a'); for (var i = 0; i <elems.length; i ++) {(function (bloqueado de línea }) (i);} // También puede usar IIFE como lo siguiente, solo usando paréntesis para incluir la función de procesamiento de clics y no incluir todo el `adEventListener`. // No importa de qué manera, ambos ejemplos se pueden bloquear con IIFE, pero descubrí que el ejemplo anterior es más legible var elems = document.getElementsByTagName ('a'); para (var i = 0; i <elems.length; i ++) {elems [i] .addeventlistener ('click', (function (funcion (bloqueadoindex) {function de retroal (e -e) alerta ('I Am Link #' + LockedInIndex); }Recuerde que en estos dos últimos ejemplos, LockedInIndex puede acceder a I sin ningún problema, pero usar un identificador con nombre diferente como un parámetro de la función puede facilitar el concepto de interpretar.
Una de las ventajas más significativas de ejecutar una función de inmediato es que incluso si no se nombra o anónima, la expresión de la función puede llamarse inmediatamente sin usar un identificador, y se puede usar un cierre sin contaminación de la variable actual.
¿Cuál es el problema con la función anónima de auto-ejecutación ("función anónima de auto-ejecutación")?
Has visto que se menciona varias veces, pero todavía no se explica tan claramente que sugeriría cambiar el término a "expresión de la función invocada inmediatamente", o, si te gusta la abreviatura.
¿Qué es la expresión de la función invocada inmediatamente? Hace una expresión de función llamada inmediatamente. Es como una expresión de funciones que te lleva a llamar.
Creo que los miembros de la comunidad de JavaScript deberían poder aceptar términos, expresión de la función invocada inmediatamente y IFE en sus artículos o declaraciones, porque creo que es más fácil entender el concepto, y el término "función anónima de auto ejecución" realmente no es lo suficientemente preciso.
// La siguiente es una función de auto-ejecutación, que llama recursivamente su propia función foo () {foo ();}; // Esta es una función anónima de auto-ejecutación. Because it has no identifier, it must use the `arguments.callee` property to call it itself var foo = function(){arguments.callee();};//This may be considered a self-executing anonymous function, but it is also feasible if you replace it with `foo` to call var foo = function(){foo();};//Some people call the function below 'self-executing Función anónima 'como esta, incluso si no es auto-ejecutiva porque no se llama a sí misma. Entonces, se solo llamó de inmediato. (function () {/*código*/} ()); // Agregar un identificador a una expresión de funciones (es decir, crear una función con nombre) será de gran ayuda para nuestra depuración. Una vez nombrado, la función ya no será anónima. (function foo () {/ * code */} ()); // iifes también se puede ejecutar por sí mismo, aunque quizás no sea el patrón más útil (function () {arguments.callee ();} ()) (function foo () {foo ();} ()) // una última cosa que notará: Esto hará un error en blackberry 5, // dentro de una función de la función llamada, ese nombre es inyefinido. Impresionante, ¿huh? (Function foo () {foo ();} ());Esperemos que el ejemplo anterior le brinde una comprensión más clara del término auto-ejecutivo que es algo engañoso porque no está ejecutando su propia función, aunque la función se ha ejecutado. Del mismo modo, no hay necesidad de señalar funciones anónimas, porque la expresión de la función invocada inmediatamente puede ser una función con nombre o una función anónima.
Último: modo de módulo
Cuando llamo a una expresión de función, si me recuerdo sobre el patrón del módulo al menos una vez, lo más probable es que lo ignore. Si no tiene el patrón del módulo en JavaScript, es muy similar a mi ejemplo a continuación, pero el valor de retorno usa un objeto en lugar de la función.
var contar = (function () {var i = 0; return {get: function () {return i;}, set: function (val) {i = val;}, increment: function () {return ++ i;}}} ()); contador.get (); // 0 contar.set (3); Counter.Increment (); // 4 Counter.Increment (); // 5 Conuter.i; // Undefined (`i` no es una propiedad del objeto devuelto) i; // referenceError: i no está definido (solo existe dentro del cierre)El método del modo de módulo no solo es bastante poderoso sino también simple. Con muy poco código, puede utilizar de manera efectiva los nombres relacionados con métodos y atributos. En un objeto, la organización de todos los códigos del módulo minimiza la contaminación de las variables globales y crea el uso de variables.