¿Qué significan los paréntesis que rodean una declaración de objeto/función/clase? [duplicar]

Resuelto user54692 asked hace 15 años • 0 respuestas

En los ejemplos de la biblioteca YUI , puedes encontrar muchos usos de esta construcción:

(function() {
    var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event,
    layout = null,
        ...
})();

Creo que los últimos paréntesis son para ejecutar la función justo después de la declaración.

... ¿Pero qué pasa con el conjunto anterior de paréntesis que rodean la declaración de función?

Creo que es una cuestión de alcance; eso es ocultar variables internas a funciones externas y posiblemente objetos globales. ¿Lo es? De manera más general, ¿cuál es la mecánica de esos paréntesis?

user54692 avatar Jan 14 '09 03:01 user54692
Aceptado

Es una función anónima autoejecutable. El primer conjunto de paréntesis contiene las expresiones que se ejecutarán y el segundo conjunto de paréntesis ejecuta esas expresiones.

Es una construcción útil cuando se intenta ocultar variables del espacio de nombres principal. Todo el código dentro de la función está contenido en el ámbito privado de la función, lo que significa que no se puede acceder a él desde fuera de la función, lo que lo hace verdaderamente privado.

Ver:

http://en.wikipedia.org/wiki/Closure_%28computer_science%29

http://peter.michaux.ca/articles/javascript-namespace

Andy Hume avatar Jan 13 '2009 20:01 Andy Hume

Andy Hume prácticamente dio la respuesta, sólo quiero agregar algunos detalles más.

Con esta construcción estás creando una función anónima con su propio entorno de evaluación o cierre, y luego la evalúas inmediatamente. Lo bueno de esto es que puede acceder a las variables declaradas antes de la función anónima y puede usar variables locales dentro de esta función sin sobrescribir accidentalmente una variable existente.

El uso de la palabra clave var es muy importante, porque en JavaScript cada variable es global por defecto, pero con la palabra clave creas una nueva variable con alcance léxico , es decir, es visible por el código entre las dos llaves . En su ejemplo, básicamente está creando alias cortos para los objetos en la biblioteca YUI, pero tiene usos más poderosos.

No quiero dejarlos sin un ejemplo de código, así que pondré aquí un ejemplo simple para ilustrar un cierre:

var add_gen = function(n) {
  return function(x) {
    return n + x;
  };
};
var add2 = add_gen(2);
add2(3); // result is 5

¿Que esta pasando aqui? En la función add_gen estás creando otra función que simplemente agregará el número n a su argumento. El truco es que las variables definidas en la lista de parámetros de la función actúan como variables de ámbito léxico, como las definidas con var .

La función devuelta se define entre llaves de la función add_gen por lo que tendrá acceso al valor de n incluso después de que la función add_gen haya terminado de ejecutarse, es por eso que obtendrá 5 al ejecutar la última línea del ejemplo.

Con la ayuda de los parámetros de función con alcance léxico, puede solucionar los "problemas" que surgen del uso de variables de bucle en funciones anónimas. Tomemos un ejemplo sencillo:

for(var i=0; i<5; i++) {
  setTimeout(function(){alert(i)}, 10);
}

El resultado "esperado" podrían ser los números del cero al cuatro, pero en su lugar obtienes cuatro casos de cinco. Esto sucede porque la función anónima en setTimeout y el bucle for usan la misma variable i , por lo que cuando se evalúen las funciones, i será 5.

Puede obtener el resultado ingenuamente esperado utilizando la técnica de su pregunta y el hecho de que los parámetros de la función tienen un alcance léxico. (He usado este enfoque en otra respuesta )

for(var i=0; i<5; i++) {
  setTimeout(
     (function(j) {
       return function(){alert(j)};
     })(i), 10);
}

Con la evaluación inmediata de la función externa, estás creando una variable completamente independiente llamada j en cada iteración, y el valor actual de i se copiará en esta variable, por lo que obtendrás el resultado que ingenuamente se esperaba desde el primer intento.

Te sugiero que intentes entender el excelente tutorial en http://ejohn.org/apps/learn/ para entender mejor los cierres, ahí es donde aprendí muchísimo.

bandi avatar Jan 14 '2009 00:01 bandi

...pero ¿qué pasa con los paréntesis de la ronda anterior que rodean toda la declaración de función?

Específicamente, hace que JavaScript interprete la construcción 'function() {...}' como una expresión de función anónima en línea. Si omitiste los corchetes:

function() {
    alert('hello');
}();

Obtendría un error de sintaxis, porque el analizador JS vería la palabra clave 'función' y asumiría que está iniciando una declaración de función de la forma:

function doSomething() {
}

...y no puedes tener una declaración de función sin un nombre de función.

Las expresiones de función y las declaraciones de función son dos construcciones diferentes que se manejan de maneras muy diferentes. Desafortunadamente, la sintaxis es casi idéntica, por lo que no sólo resulta confusa para el programador, ¡incluso el analizador tiene dificultades para saber a qué te refieres!

bobince avatar Jan 14 '2009 09:01 bobince

Simplemente para dar seguimiento a lo que Andy Hume y otros han dicho:

El '()' que rodea la función anónima es el 'operador de agrupación' tal como se define en la sección 11.1.6 de la especificación ECMA: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262 .pdf .

Tomado palabra por palabra de los documentos:

11.1.6 El operador de agrupación

La producción PrimaryExpression : ( Expression ) se evalúa de la siguiente manera:

  1. Devuelve el resultado de evaluar Expression . Este puede ser de tipo Referencia.

En este contexto, la función se trata como una expresión.

 avatar Jul 25 '2013 14:07

Algunas consideraciones sobre el tema:

  • El paréntesis:

    El navegador (motor/analizador) asocia la función de palabra clave con

    [optional name]([optional parameters]){...code...}
    

    Entonces, en una expresión como function(){}() el último paréntesis no tiene sentido.

    Ahora piensa en

    name=function(){} ; name() !?
    

Sí, el primer par de paréntesis obliga a la función anónima a convertirse en una variable (expresión almacenada) y el segundo inicia la evaluación/ejecución, por lo que ( function(){} )() tiene sentido.

  • La utilidad: ?

    1. Para ejecutar algún código al cargar y aislar las variables utilizadas del resto de la página, especialmente cuando son posibles conflictos de nombres;

    2. Reemplace eval("cadena") con

      (nueva función ("cadena"))()

    3. Ajustar código largo para el operador " =?: " como:

      resultado = exp_to_test? (función(){... código_largo ...})() : (función(){...})();

bortunac avatar Oct 20 '2011 21:10 bortunac