Solución:
Sintaxis de JavaScript 101. Aquí hay una declaración de función:
function foo() {}
Tenga en cuenta que no hay punto y coma: esto es solo una función declaración. Necesitarías una invocación, foo()
, para ejecutar la función.
Ahora, cuando agregamos el signo de exclamación aparentemente inofensivo: !function foo() {}
lo convierte en un expresión. Ahora es un expresión de función.
los !
solo no invoca la función, por supuesto, pero ahora podemos poner ()
al final: !function foo() {}()
que tiene mayor precedencia que !
e instantáneamente llama a la función.
Entonces, lo que el autor está haciendo es guardar un byte por expresión de función; una forma más legible de escribir sería esta:
(function(){})();
Finalmente, !
hace que la expresión devuelva verdadera. Esto se debe a que, de forma predeterminada, todas las expresiones de función invocadas inmediatamente (IIFE) devuelven undefined
, lo que nos deja con !undefined
cual es true
. No es particularmente útil.
La función:
function () {}
no devuelve nada (o indefinido).
A veces queremos llamar a una función justo cuando la creamos. Puede tener la tentación de probar esto:
function () {}()
pero resulta en un SyntaxError
.
Utilizando el !
operador antes de que la función haga que se trate como una expresión, por lo que podemos llamarlo:
!function () {}()
Esto también devolverá el booleano opuesto al valor de retorno de la función, en este caso true
, porque !undefined
es true
. Si desea que el valor de retorno real sea el resultado de la llamada, intente hacerlo de esta manera:
(function () {})()
Hay un buen punto para usar !
para la invocación de funciones marcadas en la guía de JavaScript de Airbnb
En general, idea para usar esta técnica en archivos separados (también conocidos como módulos) que luego se concatenan. La advertencia aquí es que se supone que los archivos deben ser concatenados por herramientas que colocan el nuevo archivo en la nueva línea (que de todos modos es un comportamiento común para la mayoría de las herramientas concat). En ese caso, usando !
ayudará a evitar errores en caso de que el módulo concatenado previamente no tenga el punto y coma al final y, sin embargo, le dará la flexibilidad de ponerlos en cualquier orden sin preocupaciones.
!function abc(){}();
!function bca(){}();
Funcionará igual que
!function abc(){}();
(function bca(){})();
pero guarda un carácter y se ve mejor arbitrario.
Y por cierto, cualquiera de +
,-
,~
,void
Los operadores tienen el mismo efecto, en términos de invocar la función, seguro que si tiene que usar algo para regresar de esa función, actuarían de manera diferente.
abcval = !function abc(){return true;}() // abcval equals false
bcaval = +function bca(){return true;}() // bcaval equals 1
zyxval = -function zyx(){return true;}() // zyxval equals -1
xyzval = ~function xyz(){return true;}() // your guess?
pero si usa patrones IIFE para un archivo, una separación de código de módulo y usa la herramienta concat para la optimización (que hace que una línea sea un trabajo de archivo), entonces la construcción
!function abc(/*no returns*/) {}()
+function bca() {/*no returns*/}()
Hará una ejecución segura de código, igual que una primera muestra de código.
Este arrojará un error porque JavaScript ASI no podrá hacer su trabajo.
!function abc(/*no returns*/) {}()
(function bca() {/*no returns*/})()
Una nota con respecto a los operadores unarios, harían un trabajo similar, pero solo en el caso, no usaron en el primer módulo. Por lo tanto, no son tan seguros si no tiene un control total sobre el orden de concatenación.
Esto funciona:
!function abc(/*no returns*/) {}()
^function bca() {/*no returns*/}()
Esto no:
^function abc(/*no returns*/) {}()
!function bca() {/*no returns*/}()