< Back

Immediately Invoked Function Expression

Aislamiento de variables y pronta ejecución


Las Expresiones de funciones inmediatamente invocadas son funciones JavaScript que se ejecutan nada más ser definidas.

Es un patrón de diseño conocido como Funciones Anónimas Auto-Ejectuadas que consiste en dos partes:

  1. La primera parte es una función anónima encerrada en el Operador de agrupación (). Esto previene el acceso de variables dentro del IIFE y tampoco "ensucian" el scope global.
  2. La segunda parte crea la función inmediatamente invocada con el comando () con el que JavaScript directamente interpretará la función.

Al hacer esto, podemos crear nuevas variables sin que colisionen con el scope original.

// 1. Primera variante de IIFE
(function() {
    alert("1. Estás usando IIFE")
}());

// 2. Segunda variante de IIFE
(function() {
    console.log("2. Estas usando IIFE")
})();

// 3. Comprobar el scope de IIFE
(function() {
    var newName = "Lucas";
    console.log(newName);
}());

(function() {
    var newName = "Maria";
    console.log(newName);
}());

console.log(window.newName);

Casos de Uso

Hay algunos casos de uso en los que es muy útil este patrón, que seguro que veréis en ciertas codebases que se enfrenten a estos problemas:

Evitar contaminar el global namespace

En codebase muy grandes es muy normal encontrarse la inicialización de multitud de variables globales. Como ya vimos en la sección de variables, es importante evitar colisiones, sobre todo si tenemos que importar múltiples archivos de distintas partes del proyecto. Es por ello que es muy útil usar IIFE para aislar estas declaraciones y que no entren en conflicto con el resto de código.

(() => {
    // Código de iniciación, por ejemplo conectarse a una base de datos
    let someVariable;
    let otherVariable;
})();

// No podremos acceder y por lo tanto no tendrán colisión someVariable y otherVariable fuera del IIFE.

Ejecutar inmediatamente una función asíncrona

function delayedFunction(x) {
    return new Promise(resolve => {
    setTimeout(() => {
        resolve(x);
    }, 2000);
    });
};

(async function(x) { // función asíncrona expresada como IIFE
    let p_a = delayedFunction(20);
    let p_b = delayedFunction(30);
    return x + await p_a + await p_b;
})(10).then(v => {
    console.log(v);  // muestra por pantalla 60 después de 2 segundos.
});

Patrón módulo

En muchas ocasiones es interesante ocultar cierta funcionalidad que estamos definiendo en un módulo, es por ello que IIFE puede ser un mecanismo interesante para poder ocultar ciertas características del código de nuestro módulo.

const chargeBattery = (percentage) => ((copyPercentage) => {
    let percentage = copyPercentage; // Esta variable es privada
    const internalMechanism = () => {
    console.log('Direccionando batería a este dispositivo');
    };
    internalMechanism();
    return {
    charge(amount) {
        if (percentage >= amount) {
        percentage -= amount;
        return percentage;
        }
        return 'Batería insuficiente';
    },
    };
})(percentage);

const firstPhone = chargeBattery(100);   // "Direccionando batería a este dispositivo"
console.log(firstPhone.percentage);      // undefined, no se puede acceder a un atributo privado
console.log(firstPhone.charge(10));      // 90
console.log(firstPhone.charge(30));      // 60
console.log(firstPhone.doBadThings);     // undefined, el método es privado
const secondPhone = chargeBattery(20);   // "Direccionando batería a este dispositivo"
console.log(secondPhone.charge(30));     // "Batería insuficiente"
console.log(secondPhone.charge(20));     // 0