Expresiones de funci贸n invocadas inmediatamente de JavaScript

    Introducci贸n

    Definir y llamar a funciones son pr谩cticas clave para dominar JavaScript y la mayor铆a de los otros lenguajes de programaci贸n. Por lo general, una funci贸n se define antes de que se llame en su c贸digo.

    Las expresiones de funci贸n invocadas inmediatamente (IIFE), pronunciadas “dudoso”, son un patr贸n com煤n de JavaScript que ejecuta una funci贸n instant谩neamente despu茅s de que se define. Los desarrolladores utilizan principalmente este patr贸n para garantizar que las variables solo sean accesibles dentro del alcance de la funci贸n definida.

    En este art铆culo, primero aprender谩 sobre las expresiones de funci贸n. Despu茅s, profundizaremos m谩s en los IIFE: c贸mo escribirlos y cu谩ndo usarlos. Finalmente, discutiremos c贸mo let La palabra clave introducida en ECMAScript 6 proporciona una alternativa m谩s limpia para algunos casos de uso de IIFE.

    驴Qu茅 son las expresiones de funci贸n?

    En JavaScript, puede definir una funci贸n de 2 formas diferentes:

    • Una declaraci贸n
    • Una expresi贸n

    Declaraciones de funciones empezar con el function palabra clave, seguida del nombre de la funci贸n y cualquier argumento que pueda tomar. Por ejemplo, podemos crear un logName funci贸n usando una declaraci贸n como esta:

    function logName(userName) {
        console.log(`${userName}, you are awesome`);
    };
    
    logName("Jane");
    

    De la definici贸n de la funci贸n, registramos cualquier valor dado en el message par谩metro a la consola. Luego llamamos a la funci贸n con “Jane, you are great!”, Que imprimir谩 ese texto en la consola.

    Al definir una funci贸n mediante declaraciones de funci贸n, la funci贸n se eleva. Una funci贸n o variable elevada se coloca en la parte superior de su alcance funcional cuando JavaScript est谩 ejecutando c贸digo.

    Nota: Alcance funcional se refiere al lugar donde se defini贸 una funci贸n. Por ejemplo, si una funci贸n foo() conten铆a una funci贸n bar() dentro de 茅l, dir铆amos que el alcance funcional de bar() es foo(). Si foo() no se defini贸 dentro de una funci贸n, entonces foo() pertenece al 谩mbito global. Las funciones de JavaScript en el 谩mbito global son accesibles para todo el c贸digo que se ejecuta con 茅l.

    En la pr谩ctica, este comportamiento le permite utilizar una funci贸n antes de definirla. Por ejemplo, el c贸digo anterior se puede reescribir as铆 y se comportar铆a de la misma manera:

    logName();
    
    function logName(name) {
        console.log(`${name}, you are awesome!`);
    };
    

    Expresiones de funciones son definiciones de funciones que se asignan a una variable. Por tanto, nuestro logName() La declaraci贸n de funci贸n puede convertirse en una expresi贸n de funci贸n si la creamos as铆:

    const logUserName = function logName(name) {
        console.log(`${name}, you are awesome!`);
    };
    
    logUserName("Jane");
    

    En este ejemplo, para llamar a la funci贸n, necesitamos usar el nombre de la variable que se proporcion贸: logUserName. Esto no cambia el comportamiento de la funci贸n, a煤n registra “Eres incre铆ble” en la consola.

    A diferencia de las declaraciones de funci贸n, las expresiones de funci贸n son no izado. Estas funciones solo est谩n disponibles cuando el int茅rprete de JavaScript procesa esa l铆nea de c贸digo.

    Por ejemplo, si intentamos llamar logUserName() antes de crearlo como una expresi贸n de funci贸n:

    logUserName("Jane");
    const logUserName = function logName(name) {
        console.log(`${name}, you are awesome!`);
    };
    

    Obtenemos el siguiente error:

    Uncaught ReferenceError: Cannot access 'logUserName' before initialization
    

    Otra diferencia entre las expresiones de funci贸n y las declaraciones de funci贸n es que las expresiones de funci贸n pueden definir funciones sin un nombre.

    Las funciones sin nombre se denominan funciones an贸nimas. Por ejemplo, logUserName() tambi茅n podr铆a definirse con una funci贸n an贸nima como esta:

    const logUserName = function (name) {
        console.log(`${name}, you are awesome!`);
    };
    

    Funciones de flecha

    Las funciones de flecha proporcionan az煤car sint谩ctico para las expresiones de funci贸n. Una reimplementaci贸n de nuestro logUserName La funci贸n que usa una funci贸n de flecha se ver铆a as铆:

    const logUserName = (name) => {
        console.log(`${name}, you are awesome!`);
    }
    

    Lea Funciones de flecha en JavaScript para obtener m谩s informaci贸n sobre esta sintaxis y c贸mo afecta el alcance de la funci贸n.

    Ahora que sabemos c贸mo crear varias expresiones de funci贸n, aprendamos a invocarlas inmediatamente.

    驴Qu茅 son las expresiones de funci贸n invocadas inmediatamente?

    Los IIFE son funciones que se ejecutan inmediatamente despu茅s de ser definidas.

    Podemos hacer que cualquier expresi贸n de funci贸n sea un IIFE envolvi茅ndola entre par茅ntesis y agregando el siguiente par de par茅ntesis al final:

    (function() {
        // Code that runs in your function
    })()
    

    Alternativamente, puede usar la sintaxis de flecha para crear un IIFE de la siguiente manera:

    (() => {
        // Code that runs in your function
    })()
    

    Los par茅ntesis que rodean la definici贸n de la funci贸n le permiten a JavaScript saber que procesar谩 una expresi贸n de funci贸n. El 煤ltimo par de par茅ntesis invoca la funci贸n.

    Variaciones de sintaxis

    Puede crear IIFE sin el primer conjunto de par茅ntesis si usa un operador unario: caracteres especiales que le dicen a JavaScript que eval煤e la siguiente expresi贸n.

    Podemos crear expresiones de funci贸n con operadores unarios como este:

    +function () {
        // Code that runs in your function
    }();
    
    -function () {
        // Code that runs in your function
    }();
    
    !function () {
        // Code that runs in your function
    }();
    
    ~function () {
        // Code that runs in your function
    }();
    
    void function () {
        // Code that runs in your function
    }();
    

    Es importante tener en cuenta que estos operadores podr铆an afectar cualquier dato devuelto por su funci贸n. Por ejemplo, el siguiente c贸digo parece que deber铆a devolver 10, pero en realidad regresa -10:

    $ node
    > -function () {return 10;}();
    -10
    >
    

    Dado que esta sintaxis unaria es menos com煤n y puede resultar confusa para los desarrolladores, por lo general se desaconseja.

    Los IIFE tambi茅n pueden tomar argumentos funcionales. Podemos pasar variables al alcance como se muestra a continuaci贸n:

    (function(arg1, arg2) {
        // Code that runs in your function
    })("hello", "world");
    

    Ahora que hemos visto c贸mo crear IIFE, veamos situaciones comunes en las que se utilizan.

    驴Cu谩ndo usar un IIFE?

    Los casos de uso m谩s comunes para IIFE son:

    • Alias 鈥嬧媎e variables globales
    • Creaci贸n de funciones y variables privadas
    • Funciones asincr贸nicas en bucles

    Alias 鈥嬧媎e variables globales

    Si tiene 2 bibliotecas que exportan un objeto con el mismo nombre, puede usar IIFE para asegurarse de que no entren en conflicto con su c贸digo. Por ejemplo, el jQuery y Efectivo Las bibliotecas de JavaScript exportan $ como su objeto principal.

    Puede envolver su c贸digo dentro de un IIFE que pasa una de las variables globales como argumento. Digamos que queremos asegurarnos de que $ se refiere a jQuery objeto, y no el cash alternativa. Puede asegurarse de que se use jQuery con el siguiente IIFE:

    (function($) {
        // Code that runs in your function
    })(jQuery);
    

    Creaci贸n de funciones y variables privadas

    Podemos usar IIFE para crear variables privadas y funciones dentro del alcance global, o cualquier otro alcance de funci贸n.

    Las funciones y variables agregadas al 谩mbito global est谩n disponibles para todos los scripts que se cargan en una p谩gina. Digamos que tenemos una funci贸n generateMagicNumber(), que devolvi贸 un n煤mero aleatorio entre 900 y 1000 inclusive, y una variable favoriteNumber en nuestro archivo JavaScript.

    Podemos escribirlos as铆:

    function generateMagicNumber() {
        return Math.floor(Math.random() * 100) + 900;
    }
    
    console.log("This is your magic number: " + generateMagicNumber());
    
    var favoriteNumber = 5;
    console.log("Twice your favorite number is " + favoriteNumber * 2);
    

    Si cargamos otros archivos JavaScript en nuestro navegador, tambi茅n obtienen acceso a generateMagicNumber() y favoriteNumber. Para evitar que los usen o los editen, encapsulamos nuestro c贸digo en un IIFE:

    (function () {
        function generateMagicNumber() {
            return Math.floor(Math.random() * 100) + 900;
        }
    
        console.log("This is your magic number: " + generateMagicNumber());
    
        var favoriteNumber = 5;
        console.log("Twice your favorite number is " + favoriteNumber * 2);
    })();
    

    Funciona igual, pero ahora generateMagicNumber() y favoriteNumber solo son accesibles en nuestro script.

    Funciones asincr贸nicas en bucles

    El comportamiento de JavaScript sorprende a muchos cuando las devoluciones de llamada se ejecutan en bucles. Por ejemplo, contemos de 1 a 5 en JavaScript, dejando un espacio de 1 segundo entre cada vez que registramos un mensaje. Una implementaci贸n ingenua ser铆a:

    for (var i = 1; i <= 5; i++) {
        setTimeout(function () {
            console.log('I reached step ' + i);
        }, 1000 * i);
    }
    

    Si ejecuta este c贸digo, obtendr谩 el siguiente resultado:

    $ node naiveCallbackInLoop.js
    I reached step 6
    I reached step 6
    I reached step 6
    I reached step 6
    I reached step 6
    

    Si bien la salida se imprimir铆a 1 segundo despu茅s de la otra, cada l铆nea imprime que llegaron al paso 6. 驴Por qu茅?

    Cuando JavaScript encuentra c贸digo asincr贸nico, pospone la ejecuci贸n de la devoluci贸n de llamada hasta que se completa la tarea asincr贸nica. As铆 es como permanece sin bloqueo. En este ejemplo, el console.log() La instrucci贸n se ejecutar谩 solo despu茅s de que haya transcurrido el tiempo de espera.

    JavaScript tambi茅n cre贸 un cierre para nuestra devoluci贸n de llamada. Los cierres son una combinaci贸n de una funci贸n y su alcance cuando fue creado. Con cierres, nuestra devoluci贸n de llamada puede acceder a la variable i a pesar de for loop ya ha terminado de ejecutarse.

    Sin embargo, nuestra devoluci贸n de llamada solo tiene acceso al valor de i en el momento de su ejecuci贸n. Como el c贸digo dentro del setTimeout() todas las funciones fueron diferidas, for El bucle se termin贸 con i siendo igual a 6. Es por eso que todos registran que llegaron al paso 6.

    Este problema se puede resolver con un IIFE:

    for (var i = 1; i <= 5; i++) {
        (function (step) {
            setTimeout(function() {
                console.log('I reached step ' + step);
            }, 1000 * i);
        })(i);
    }
    

    Al usar un IIFE, creamos un nuevo alcance para nuestra funci贸n de devoluci贸n de llamada. Nuestro IIFE toma un par谩metro step. Cada vez que se llama a nuestro IIFE, le damos el valor actual de i como su argumento. Ahora, cuando la devoluci贸n de llamada est茅 lista para ejecutarse, su cierre tendr谩 el valor correcto de step.

    Si ejecutamos este fragmento de c贸digo, veremos el siguiente resultado:

    $ node iifeCallbackInLoop.js
    I reached step 1
    I reached step 2
    I reached step 3
    I reached step 4
    I reached step 5
    

    Si bien los IIFE resuelven nuestro problema con cambios m铆nimos en el c贸digo, echemos un vistazo a c贸mo las caracter铆sticas de ES6 pueden facilitar la ejecuci贸n de c贸digo asincr贸nico en bucles.

    Bloquear alcance con let y const

    ES6 agreg贸 el let y const palabras clave para crear variables en JavaScript. Variables declaradas con let o const son alcance de bloque. Esto significa que solo se puede acceder a ellos dentro de su bloque circundante, una regi贸n encerrada por llaves { }.

    Vamos a contar de 1 a 5 en intervalos de 1 segundo usando el let palabra clave en lugar de var:

    for (let i = 1; i <= 5; i++) {
        setTimeout(function () {
            console.log('I reached step ' + i);
        }, 1000 * i);
    }
    

    Obtendremos el siguiente resultado cuando ejecutemos este c贸digo:

    $ node es6CallbackInLoop.js
    I reached step 1
    I reached step 2
    I reached step 3
    I reached step 4
    I reached step 5
    

    Ahora que la variable i tiene un alcance de bloque, los cierres para nuestra funci贸n de devoluci贸n de llamada obtienen el valor apropiado de i cuando finalmente se ejecutan. Esto es m谩s conciso que nuestra implementaci贸n IIFE.

    Utilizando let es la forma preferida de ejecutar funciones asincr贸nicas en un bucle,

    Conclusi贸n

    Una expresi贸n de funci贸n invocada inmediatamente (IIFE) es una funci贸n que se ejecuta instant谩neamente despu茅s de su definici贸n. Este patr贸n se ha utilizado para crear alias de variables globales, hacer que las variables y funciones sean privadas y garantizar que el c贸digo asincr贸nico en los bucles se ejecute correctamente.

    Si bien es popular, hemos visto c贸mo los cambios en ES6 pueden eliminar la necesidad de usar IIFE en JavaScript moderno. Sin embargo, dominar este patr贸n tambi茅n nos da una comprensi贸n m谩s profunda del alcance y el cierre, y ser谩 especialmente 煤til para mantener el c贸digo JavaScript heredado.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *