otra - pasar funcion como parametro javascript
Explicar la sintaxis de la función anónima encapsulada. (9)
Resumen
¿Puede explicar el razonamiento detrás de la sintaxis para funciones anónimas encapsuladas en JavaScript? ¿Por qué funciona esto: (function(){})();
pero esto no: function(){}();
?
Lo que yo sé
En JavaScript, uno crea una función nombrada como esta:
function twoPlusTwo(){
alert(2 + 2);
}
twoPlusTwo();
También puede crear una función anónima y asignarla a una variable:
var twoPlusTwo = function(){
alert(2 + 2);
};
twoPlusTwo();
Puede encapsular un bloque de código creando una función anónima, luego envolviéndola entre corchetes y ejecutándola inmediatamente:
(function(){
alert(2 + 2);
})();
Esto es útil cuando se crean scripts modularizados, para evitar saturar el alcance actual, o el alcance global, con variables potencialmente conflictivas, como en el caso de los scripts de Greasemonkey, los complementos de jQuery, etc.
Ahora, entiendo por qué esto funciona. Los corchetes encierran el contenido y exponen solo el resultado (estoy seguro de que hay una mejor manera de describirlo), como con (2 + 2) === 4
.
Lo que no entiendo
Pero no entiendo por qué esto no funciona igual de bien:
function(){
alert(2 + 2);
}();
¿Me puedes explicar eso?
A pesar de que esta es una vieja pregunta y respuesta, analiza un tema que, hasta el día de hoy, hace que muchos desarrolladores formen un círculo. No puedo contar el número de candidatos a desarrollador de JavaScript que he entrevistado, que no pudieron decirme la diferencia entre una declaración de función y una expresión de función y que no tenían ni idea de qué es una expresión de función invocada de inmediato.
Sin embargo, me gustaría mencionar una cosa muy importante que es que el fragmento de código de Premasagar no funcionaría incluso si le hubiera dado un identificador de nombre.
function someName() {
alert(2 + 2);
}();
La razón por la que esto no funcionaría es que el motor de JavaScript interpreta esto como una declaración de función seguida por un operador de agrupación completamente no relacionado que no contiene expresión, y los operadores de agrupación deben contener una expresión. Según JavaScript, el fragmento de código anterior es equivalente al siguiente.
function someName() {
alert(2 + 2);
}
();
Otra cosa que me gustaría señalar que puede ser de alguna utilidad para algunas personas es que cualquier identificador de nombre que proporcione para una expresión de función es bastante inútil en el contexto del código, excepto desde dentro de la propia definición de la función.
var a = function b() {
// do something
};
a(); // works
b(); // doesn''t work
var c = function d() {
window.setTimeout(d, 1000); // works
};
Por supuesto, usar identificadores de nombres con las definiciones de sus funciones siempre es útil cuando se trata de depurar el código, pero eso es algo completamente distinto ... :-)
En javascript, esto se denomina expresión de función de invocación inmediata (IIFE) .
Para que sea una expresión de función tienes que:
adjuntarlo usando ()
colocar un operador vacío antes de que
asignarlo a una variable.
De lo contrario, se tratará como definición de función y, a continuación, no podrá llamarlo / invocarlo de la siguiente manera:
function (arg1) { console.log(arg1) }();
Lo anterior te dará error. Porque solo puedes invocar una expresión de función inmediatamente.
Esto se puede lograr de dos maneras: Camino 1:
(function(arg1, arg2){
//some code
})(var1, var2);
Camino 2:
(function(arg1, arg2){
//some code
}(var1, var2));
Camino 3:
void function(arg1, arg2){
//some code
}(var1, var2);
forma 4:
var ll = function (arg1, arg2) {
console.log(arg1, arg2);
}(var1, var2);
Todo lo anterior invocará inmediatamente la expresión de la función.
Esos paréntesis adicionales crean funciones anónimas adicionales entre el espacio de nombres global y la función anónima que contiene el código. Y en las funciones de Javascript declaradas dentro de otras funciones solo se puede acceder al espacio de nombres de la función principal que las contiene. Como existe un objeto adicional (función anónima) entre el alcance global y el alcance del código real, no se retiene.
Grandes respuestas ya han sido publicadas. Pero quiero tener en cuenta que las declaraciones de función devuelven un registro de finalización vacío:
14.1.20 - Semántica en tiempo de ejecución: evaluación
FunctionDeclaration :
function
BindingIdentifier(
FormalParameters)
{
FunctionBody}
- Retorno NormalCompletion (vacío).
Este hecho no es fácil de observar, porque la mayoría de las formas de intentar obtener el valor devuelto convertirán la declaración de función en una expresión de función. Sin embargo, eval
muestra:
var r = eval("function f(){}");
console.log(r); // undefined
Llamar a un registro de finalización vacío no tiene sentido. Es por eso que la function f(){}()
no puede funcionar. De hecho, el motor JS ni siquiera intenta llamarlo, los paréntesis se consideran parte de otra declaración.
Pero si envuelve la función entre paréntesis, se convierte en una expresión de función:
var r = eval("(function f(){})");
console.log(r); // function f(){}
Las expresiones de función devuelven un objeto de función. Y por lo tanto puedes llamarlo: (function f(){})()
.
No funciona porque se está analizando como FunctionDeclaration
, y el nombre identificador de las declaraciones de funciones es obligatorio .
Cuando lo rodea con paréntesis, se evalúa como una expresión de función, y las expresiones de función pueden ser nombradas o no.
La gramática de una FunctionDeclaration
ve así:
function Identifier ( FormalParameterListopt ) { FunctionBody }
Y FunctionExpression
s:
function Identifieropt ( FormalParameterListopt ) { FunctionBody }
Como puede ver, el token de Identifier
( opción de identificador) en FunctionExpression
es opcional, por lo tanto, podemos tener una expresión de función sin un nombre definido:
(function () {
alert(2 + 2);
}());
O expresión de función nombrada :
(function foo() {
alert(2 + 2);
}());
Los paréntesis (formalmente llamados el operador de agrupación ) pueden rodear solo expresiones, y se evalúa una función.
Las dos producciones gramaticales pueden ser ambiguas y pueden verse exactamente iguales, por ejemplo:
function foo () {} // FunctionDeclaration
0,function foo () {} // FunctionExpression
El analizador sabe si es una FunctionDeclaration
o una FunctionExpression
, dependiendo del contexto en el que aparezca.
En el ejemplo anterior, el segundo es una expresión porque el operador de coma también puede manejar solo expresiones.
Por otro lado, los FunctionDeclaration
s podrían aparecer solo en lo que se denomina código de " Program
", es decir, código fuera del alcance global y dentro del FunctionBody
de otras funciones.
Deben evitarse las funciones dentro de bloques, ya que pueden llevar a un comportamiento impredecible, por ejemplo:
if (true) {
function foo () { alert(''true''); }
} else {
function foo () { alert(''false!''); }
}
foo(); // true? false? why?
El código anterior debería producir realmente un SyntaxError
, ya que un Block
solo puede contener sentencias (y la Especificación ECMAScript no define ninguna sentencia de función), pero la mayoría de las implementaciones son tolerantes, y simplemente tomarán la segunda función, la que alerta ''false!''
.
Las implementaciones de Mozilla -Rhino, SpiderMonkey, - tienen un comportamiento diferente. Su gramática contiene una Declaración de función no estándar , lo que significa que la función se evaluará en tiempo de ejecución , no en tiempo de análisis, como ocurre con las Declaraciones de FunctionDeclaration
. En esas implementaciones obtendremos la primera función definida.
Las funciones se pueden declarar de diferentes maneras, compare lo siguiente :
1- Una función definida con el constructor de Function asignado a la variable se multiplica :
var multiply = new Function("x", "y", "return x * y;");
2- Una declaración de función de una función llamada multiplicar :
function multiply(x, y) {
return x * y;
}
3- Una expresión de función asignada a la variable multiplica :
var multiply = function (x, y) {
return x * y;
};
4- Una función denominada expresión func_name , asignada a la variable multiplica :
var multiply = function func_name(x, y) {
return x * y;
};
Quizás la respuesta más corta sería que
function() { alert( 2 + 2 ); }
Es una función literal que define una función (anónima). Una pareja () adicional, que se interpreta como una expresión, no se espera en el nivel superior, solo literales.
(function() { alert( 2 + 2 ); })();
está en una declaración de expresión que invoca una función anónima.
Se pueden usar con parámetros-argumentos como
var x = 3;
var y = 4;
(function(a,b){alert(a + b)})(x,y)
resultaría como 7
Solo tengo otro pequeño comentario. Tu código funcionará con un pequeño cambio:
var x = function(){
alert(2 + 2);
}();
Uso la sintaxis anterior en lugar de la versión más extendida:
var module = (function(){
alert(2 + 2);
})();
porque no conseguí que la sangría funcionara correctamente para archivos javascript en vim. Parece que a vim no le gustan las llaves dentro de paréntesis abiertos.
(function(){
alert(2 + 2);
})();
La anterior es una sintaxis válida porque todo lo que se pase entre paréntesis se considera como expresión de función.
function(){
alert(2 + 2);
}();
Lo anterior no es sintaxis válida. Debido a que el analizador de sintaxis del script de Java busca el nombre de la función después de la palabra clave de la función, ya que no encuentra nada, genera un error.