Una expresión de función inmediatamente invocada (o IIFE , pronunciada "dudosa", IPA /ˈɪf.i/) es un modismo del lenguaje de programación que produce un alcance léxico utilizando el alcance de la función . Era popular en JavaScript [1] como método para admitir la programación modular antes de la introducción de soluciones más estandarizadas como los módulos CommonJS y ES . [2]
Las expresiones de función invocadas inmediatamente se pueden utilizar para evitar el levantamiento de variables desde dentro de los bloques, proteger contra la contaminación del entorno global y simultáneamente permitir el acceso público a los métodos manteniendo la privacidad de las variables definidas dentro de la función.
Las expresiones de funciones inmediatamente invocadas se pueden escribir de varias maneras diferentes. [3] Una convención común es encerrar la expresión de la función (y opcionalmente su operador de invocación) con el operador de agrupación, [4] entre paréntesis, para indicarle explícitamente al analizador que espere una expresión. De lo contrario, en la mayoría de las situaciones, cuando el analizador encuentra la function
palabra clave, la trata como una declaración de función (declaración) y no como una expresión de función. [5] [6]
( función () { /* ... */ })(); ( función () { /* ... */ }()); (() => { /* ... */ })(); // Con funciones de flecha de ES6 (aunque los paréntesis solo se permiten en el exterior)
Hay otras formas de hacer cumplir una expresión de función: [ cita necesaria ]
! función () { /* ... */ }(); ~ función () { /* ... */ }(); - función () { /* ... */ }(); + función () { /* ... */ }(); función vacía () { /* ... */ }(); eliminar función () { /* ... */ }(); tipo de función () { /* ... */ }(); función de espera () { /* ... */ }();
En contextos donde se espera una expresión, no es necesario incluirla entre paréntesis:
let f = función () { /* ... */ }(); verdadero && función () { /* ... */ }(); 0 , función () { /* ... */ }();
Pasar variables al alcance se realiza de la siguiente manera:
( función ( a , b ) { /* ... */ })( "hola" , "mundo" );
Un paréntesis inicial es un caso en el que la inserción automática de punto y coma (ASI) en JavaScript puede causar problemas; en cambio, la expresión se interpreta como una llamada al último término de la línea anterior. En algunos estilos que omiten el punto y coma opcional, el punto y coma se coloca delante del paréntesis y se conoce como punto y coma defensivo . [7] [8] Por ejemplo:
a = b + c ;( función () { // código })();
...para evitar ser analizado como c()
.
La clave para comprender patrones de diseño como IIFE es darse cuenta de que antes de ES6, JavaScript solo presentaba un alcance de función (por lo tanto, carecía de alcance de bloque ), pasando valores por referencia dentro de cierres . [9] Este ya no es el caso, ya que la versión ES6 de JavaScript implementa el alcance del bloque utilizando las palabras clave new let
y const
. [10]
La falta de alcance del bloque significa que las variables definidas dentro (por ejemplo) de un bucle for tendrán su definición "elevada" a la parte superior de la función adjunta. Evaluar una función que depende de variables modificadas por la función externa (incluso por iteración) puede resultar difícil. Podemos ver esto sin un bucle si actualizamos un valor entre la definición y la invocación de la función. [11]
let v , getValue ; v = 1 ; getValue = function () { return v ; }; v = 2 ; obtenerValor (); // 2
Si bien el resultado puede parecer obvio cuando se actualiza v
manualmente, puede producir resultados no deseados cuando getValue()
se define dentro de un bucle.
De ahora en adelante, la función pasa v
como argumento y se invoca inmediatamente, preservando el contexto de ejecución de la función interna. [12]
let v , getValue ; v = 1 ; getValue = ( función ( x ) { función de retorno () { retorno x ; }; })( v ); v = 2 ; obtenerValor (); // 1
Esto es equivalente al siguiente código:
let v , getValue ; v = 1 ; función f ( x ) { función de retorno () { retorno x ; }; }; obtenerValor = f ( v ); v = 2 ; obtenerValor (); // 1
Los IIFE también son útiles para establecer métodos privados para funciones accesibles y al mismo tiempo exponer algunas propiedades para su uso posterior. [13] El siguiente ejemplo proviene de la publicación de Alman sobre IIFE. [1]
// "contador" es una función que devuelve un objeto con propiedades, que en este caso son funciones. let contador = ( function () { let i = 0 ; return { obtener : función () { return i ; }, establecer : función ( val ) { i = val ; }, incremento : función () { retorno ++ i ; } }; })(); // Estas llamadas acceden a las propiedades de la función devueltas por "contador". encimera . conseguir (); // 0 contador . conjunto ( 3 ); encimera . incremento (); // 4 contadores . incremento (); // 5
Si intentamos acceder counter.i
desde el entorno global, será indefinido, ya que está incluido dentro de la función invocada y no es una propiedad de counter
. Asimismo, si intentamos acceder i
, resultará en un error, ya que no lo hemos declarado i
en el entorno global.
Originalmente conocida como una "función anónima autoejecutable", [14] Ben Alman introdujo más tarde el término actual IIFE como un nombre semánticamente más preciso para el modismo, poco después de que surgiera su discusión en comp.lang.javascript. [1] [15] [16]
En particular, las funciones invocadas inmediatamente no necesitan ser inherentemente anónimas, y el modo estricto de ECMAScript 5 lo prohíbe arguments.callee
, [17] convirtiendo el término original en un nombre inapropiado .