¡Función javascript líder! sintaxis


204

He estado viendo esta sintaxis en algunas bibliotecas ahora y me pregunto cuál es el beneficio. (tenga en cuenta que estoy al tanto de los cierres y de lo que está haciendo el código, solo me preocupan las diferencias sintácticas)

!function(){
  // do stuff
}();

Como alternativa a lo más común

(function(){
  // do stuff
})();

para auto invocar funciones anónimas.

Me pregunto algunas cosas. En primer lugar, ¿qué está permitiendo que el mejor ejemplo funcione realmente? ¿Por qué es necesaria la explosión para que esta afirmación sea sintácticamente correcta? También me dijeron que +funciona, y estoy seguro de que algunos otros, en lugar de!

Segundo, ¿cuál es el beneficio? Todo lo que puedo decir es que salva un solo personaje, pero no puedo imaginar que sea un beneficio tan grande para atraer a numerosos adoptantes. ¿Hay algún otro beneficio que me estoy perdiendo?

La única otra diferencia que puedo ver sería el valor de retorno de la función de invocación automática, pero en estos dos ejemplos, realmente no nos importa el valor de retorno de la función, ya que se usa solo para crear un cierre. Entonces, ¿alguien puede decirme por qué uno podría usar la primera sintaxis?


A Frameworks le gusta guardar tantos caracteres como sea posible que un minificador no puede optimizar.
alex

El primer beneficio me viene a la cabeza es que puedes crear un sandbox como, (function ($) {...}) (jQuery);
JS Taylor

2
ambos ejemplos logran esto. Como se mencionó, entiendo lo que están haciendo estas funciones, estoy más interesado en las diferencias sintácticas
brad

8
Lo atribuyo a la necesidad, nee, requisito de ser lindo de una manera que sea más sofisticada que la tripulación anterior. "¡Oh, esos paganos entre paréntesis, los tenemos!"
Jared Farrish

2
Nunca supe de esto, increíble. Me gusta !porque enfatiza que se está ejecutando.
cdmckay

Respuestas:


97

Idealmente, debería poder hacer todo esto simplemente como:

function(){
  // do stuff
}(); 

Eso significa declarar una función anónima y ejecutarla. Pero eso no funcionará debido a los detalles de la gramática JS.

Entonces, la forma más corta de lograr esto es usar alguna expresión, por ejemplo, UnaryExpression (y así CallExpression):

!function(){
  // do stuff
}(); 

O por diversión:

-function(){
  // do stuff
}(); 

O:

+function(){
  // do stuff
}(); 

O incluso:

~function(){
  // do stuff
  return 0;
}( );

3
Entonces, ¿el único beneficio es la brevedad?
Brad

12
He agregado todas las opciones anteriores a la prueba de rendimiento en: jsperf.com/bang-function
Shaz

55
Expresividad diría. La velocidad realmente no importa en tales casos, ya que se ejecuta una vez.
c-smile

1
Por curiosidad, noté que ninguna explosión y explosión funcionan más rápido, pero al menos en algún lugar de la evolución de Chrome, la explosión se volvió más rápida que ninguna explosión. (Probablemente estadísticamente insignificante pero ...) ¿Hay alguna razón por la cual? No sé mucho sobre el código debajo del capó, pero lo encuentro bastante fascinante.
jmk2142

Dos de sus operadores unarios pueden interpretarse como binarios si falta un punto y coma. El primero y el último son los más seguros de esos ejemplos.

73

En Javascript, functionse espera que una línea que comience sea ​​una declaración de función y se vea como

function doSomething() {
}

Una función de auto invocación como

function(){
  // do stuff
}();

no se ajusta a esa forma (y provocará un error de sintaxis en el primer par de apertura porque no hay nombre de función), por lo que los corchetes se utilizan para delinear una expresión de función anónima .

(function(){
  // do stuff
})();

Pero cualquier cosa que cree una expresión (a diferencia de una declaración de función) servirá, por lo tanto, el !. Le está diciendo al intérprete que esto no es una declaración de función. Aparte de eso, la precedencia del operador dicta que la función se invoque antes de la negación.

No estaba al tanto de esta convención, pero si se vuelve común, puede contribuir a la legibilidad. Lo que quiero decir es que cualquiera que lea la !functionparte superior de un gran bloque de código esperará una auto invocación, de la forma en que ya estamos condicionados a esperar lo mismo cuando lo veamos (function. Excepto que perderemos esos molestos paréntesis. Esperaría que esa sea la razón, a diferencia de cualquier ahorro en velocidad o recuento de caracteres.


Esta "línea que comienza con la función se espera ..." parece bastante difusa. ¿Qué hay de esto:var foo = {CR/LF here} function bar() {}
c-sonrisa

45

Además de las cosas que ya se dijeron, la sintaxis con el! es útil si escribe javascript sin punto y coma:

var i = 1
!function(){
  console.log('ham')
}()

i = 2
(function(){
  console.log('cheese')
})()

El primer ejemplo genera 'ham' como se esperaba, pero el segundo arrojará un error porque la declaración i = 2 no finaliza debido al siguiente paréntesis.

También en los archivos JavaScript concatenados no tiene que preocuparse si al código anterior le faltan puntos y coma. Entonces no es necesario lo común; (function () {}) (); para asegurarte de que el tuyo no se rompa.

Sé que mi respuesta es un poco tarde, pero creo que aún no se ha mencionado :)


66
+1 para la sugerencia y los recuerdos ... a nadie le gusta escribir javascript sin punto y coma en estos días.
Pablo Grisafi

44
Twitter Bootstrap es todo JS sin punto y coma, y ​​es bastante nuevo ... (perdón si el comentario anterior fue de naturaleza sarcástica y lo extrañé).
brandwaffle

2
Esto no es realmente cierto. Considere el siguiente ejemplo:! Function () {console.log ("ham");} ()! Function () {console.log ("cheese")} (); aparece un error: "SyntaxError: token inesperado"
heavysixer

Sí, tiene usted razón. Hay un error, si los pone en la misma línea. No pensé en eso. Pero, ningún script / lib de concatenación que he usado hasta ahora hace eso. Y cuando minimiza y concat sus archivos se agregan puntos y comas. Entonces, honestamente, no puedo imaginar un caso en el que te encuentres con ese problema. Por otro lado, son las 2 am aquí y podría ser ignorante :)
Smoe

6

Por un lado, jsPerf muestra que usar !(UnaryExpression's) suele ser más rápido. A veces resultan iguales, pero cuando no lo son, no he visto que el no golpeado triunfe demasiado sobre los demás todavía: http://jsperf.com/bang-function

Esto se probó en el último Ubuntu con el Chrome más antiguo (por decir ..), versión 8. Por lo tanto, los resultados pueden diferir, por supuesto.

Editar: ¿Qué tal algo loco como delete?

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

o void?

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

¡interesante! Obtuve alrededor de 50/50, aunque en Safari en cuanto a velocidad, sin golpes ciertamente se mantuvo firme. Me pregunto si hay alguna teoría sobre las posibles diferencias de velocidad.
Brad

@brad Debe tener algo que ver con el safari, si nos fijamos en las pruebas, la mayoría de los otros navegadores parecen estar favoreciendo !. Pero también me gustaría encontrar una teoría sobre esto también :)
Shaz

3
i como nula, ya que está diciendo explícitamente "no me importa acerca de valor de retorno", y porque me recuerda a las convenciones en otros idiomas
code_monk

4

Como puede ver aquí , la mejor manera de hacer métodos auto invocados en JavaScript es usar:

(function(){}()); -> 76,827,475 ops/sec

!function(){}();  -> 69,699,155 ops/sec

(function(){})(); -> 69,564,370 ops/sec

1
Dudo que el rendimiento sea la razón para usar una sintaxis u otra. A 70 millones de operaciones / segundo, declarar que el cierre será miles de veces más rápido que el código interno de todos modos
Eloims,

3

Entonces, con negar "!" y todos los demás operadores unarios como +, -, ~, eliminar, anular, se ha dicho mucho, solo para resumir:

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

O

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

O

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

Y algunos casos más con operadores binarios para divertirse :)

1 > function() {
   alert("Hi!"); 
}();

O

1 * function() {
   alert("Hi!"); 
}();

O

1 >>> function() {
   alert("Hi!"); 
}();

O incluso

1 == function() {
   alert("Hi!"); 
}();

Dejando el ternario para otra persona chicos :)


12
0?0:function() { alert("Hi!"); }();
daniel1426

Bingo, Dan! Tenemos el ternario;)
Arman McHitarian
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.