¿Por qué es necesario invocar una función anónima en la misma línea?

Resuelto palig asked hace 15 años • 19 respuestas

Estuve leyendo algunas publicaciones sobre cierres y vi esto en todas partes, pero no hay una explicación clara de cómo funciona; cada vez me dijeron que lo usara...:

// Create a new anonymous function, to use as a wrapper
(function(){
    // The variable that would, normally, be global
    var msg = "Thanks for visiting!";

    // Binding a new function to a global object
    window.onunload = function(){
        // Which uses the 'hidden' variable
        alert( msg );
    };
// Close off the anonymous function and execute it
})();

Ok, veo que crearemos una nueva función anónima y luego la ejecutaremos. Entonces, después de eso, este código simple debería funcionar (y funciona):

(function (msg){alert(msg)})('SO');

Mi pregunta es ¿qué tipo de magia ocurre aquí? Pensé eso cuando escribí:

(function (msg){alert(msg)})

entonces se crearía una nueva función sin nombre como la función ""(msg)...

pero entonces ¿por qué esto no funciona?

(function (msg){alert(msg)});
('SO');

¿Por qué tiene que estar en la misma línea?

¿Podrías indicarme algunas publicaciones o darme una explicación?

palig avatar Jul 17 '09 03:07 palig
Aceptado

Suelte el punto y coma después de la definición de la función.

(function (msg){alert(msg)})
('SO');

Lo anterior debería funcionar.

Página de demostración: https://jsfiddle.net/e7ooeq6m/

He discutido este tipo de patrón en esta publicación:

preguntas jQuery y $

EDITAR:

Si observa la especificación del script ECMA , hay 3 formas de definir una función. (Página 98, Sección 13 Definición de función)

1. Usando el constructor de funciones

var sum = new Function('a','b', 'return a + b;');
alert(sum(10, 20)); //alerts 30

2. Uso de la declaración de función.

function sum(a, b)
{
    return a + b;
}

alert(sum(10, 10)); //Alerts 20;

3. Expresión de función

var sum = function(a, b) { return a + b; }

alert(sum(5, 5)); // alerts 10

Entonces te preguntarás, ¿cuál es la diferencia entre declaración y expresión?

De la especificación ECMA Script:

Declaración de función: identificador de función (FormalParameterListopt) {Cuerpo de función}

FunctionExpression: función Identifieropt (FormalParameterListopt){ FunctionBody}

Si observa, el 'identificador' es opcional para la expresión de función. Y cuando no proporcionas un identificador, creas una función anónima. No significa que no pueda especificar un identificador.

Esto significa que lo siguiente es válido.

var sum = function mySum(a, b) { return a + b; }

Un punto importante a tener en cuenta es que puede usar 'mySum' solo dentro del cuerpo de la función mySum, no fuera. Vea el siguiente ejemplo:

var test1 = function test2() { alert(typeof test2); }

alert(typeof(test2)); //alerts 'undefined', surprise! 

test1(); //alerts 'function' because test2 is a function.

Demo en vivo

Compara esto con

 function test1() { alert(typeof test1) };

 alert(typeof test1); //alerts 'function'

 test1(); //alerts 'function'

Armados con este conocimiento, intentemos analizar su código.

Cuando tienes un código como,

    function(msg) { alert(msg); }

Creaste una expresión de función. Y puede ejecutar esta expresión de función envolviéndola entre paréntesis.

    (function(msg) { alert(msg); })('SO'); //alerts SO.
SolutionYogi avatar Jul 16 '2009 20:07 SolutionYogi

Se llama función autoinvocada.

Lo que estás haciendo cuando llamas (function(){})es devolver un objeto de función. Cuando lo agrega (), se invoca y se ejecuta cualquier cosa en el cuerpo. Denota el ;final de la declaración, por eso falla la segunda invocación.

seth avatar Jul 16 '2009 20:07 seth

Una cosa que encontré confusa es que los "()" son operadores de agrupación.

Aquí está su función básica declarada.

Ex. 1:

var message = 'SO';

function foo(msg) {
    alert(msg);
}

foo(message);

Las funciones son objetos y se pueden agrupar. Entonces, coloquemos pares alrededor de la función.

Ex. 2:

var message = 'SO';

function foo(msg) {  //declares foo
    alert(msg);
}

(foo)(message);     // calls foo

Ahora, en lugar de declarar y llamar inmediatamente a la misma función, podemos usar una sustitución básica para declararla tal como la llamamos.

Ex. 3.

var message = 'SO';

(function foo(msg) {
    alert(msg);
})(message);          // declares & calls foo

Finalmente, ¡no necesitamos ese foo adicional porque no usamos el nombre para llamarlo! Las funciones pueden ser anónimas.

Ex. 4.

var message = 'SO';

(function (msg) {   // remove unnecessary reference to foo
    alert(msg);
})(message);

Para responder a su pregunta, consulte el Ejemplo 2. Su primera línea declara alguna función sin nombre y la agrupa, pero no la llama. La segunda línea agrupa una cadena. Ambos no hacen nada. (El primer ejemplo de Vincent).

(function (msg){alert(msg)});  
('SO');                       // nothing.

(foo); 
(msg); //Still nothing.

Pero

(foo)
(msg); //works
Benxamin avatar Apr 20 '2011 20:04 Benxamin

Una función anónima no es una función con el nombre "". Es simplemente una función sin nombre.

Como cualquier otro valor en JavaScript, una función no necesita un nombre para crearse. Aunque es mucho más útil vincularlo a un nombre como cualquier otro valor.

Pero como cualquier otro valor, a veces querrás usarlo sin vincularlo a un nombre. Ése es el patrón de autoinvocación.

Aquí hay una función y un número, no vinculados, no hacen nada y nunca pueden usarse:

function(){ alert("plop"); }
2;

Entonces tenemos que almacenarlos en una variable para poder usarlos, como cualquier otro valor:

var f = function(){ alert("plop"); }
var n = 2;

También puedes usar azúcar sintático para vincular la función a una variable:

function f(){ alert("plop"); }
var n = 2;

Pero si no es necesario nombrarlos y generaría más confusión y menos legibilidad, puede usarlos de inmediato.

(function(){ alert("plop"); })(); // will display "plop"
alert(2 + 3); // will display 5

Aquí, mi función y mis números no están vinculados a una variable, pero aún pueden usarse.

Dicho así, parece que la función de autoinvocación no tiene valor real. Pero debes tener en cuenta que el delimitador de alcance de JavaScript es la función y no el bloque ({}).

Entonces, una función de autoinvocación en realidad tiene el mismo significado que un bloque de C++, C# o Java. Lo que significa que la variable creada dentro no se "filtrará" fuera del alcance. Esto es muy útil en JavaScript para no contaminar el ámbito global.

Vincent Robert avatar Jul 16 '2009 20:07 Vincent Robert

Así es como funciona JavaScript. Puedes declarar una función con nombre:

function foo(msg){
   alert(msg);
}

Y llámalo:

foo("Hi!");

O puede declarar una función anónima:

var foo = function (msg) {
    alert(msg);
}

Y llama a eso:

foo("Hi!");

O simplemente nunca podrás vincular la función a un nombre:

(function(msg){
   alert(msg);
 })("Hi!");

Las funciones también pueden devolver funciones:

function make_foo() {
    return function(msg){ alert(msg) };
}

(make_foo())("Hi!");

No vale la pena que cualquier variable definida con "var" en el cuerpo de make_foosea cerrada por cada función devuelta por make_foo. Esto es un cierre y significa que cualquier cambio realizado en el valor por una función será visible para otra.

Esto le permite encapsular información, si lo desea:

function make_greeter(msg){
    return function() { alert(msg) };
}

var hello = make_greeter("Hello!");

hello();

Así es como funcionan casi todos los lenguajes de programación excepto Java.

jrockway avatar Jul 16 '2009 20:07 jrockway