toptal reveal practices patterns pattern best and javascript design-patterns iife

reveal - singleton javascript



En JavaScript, ¿cuál es la ventaja de! Function(){}() over(function(){})()? (6)

Bueno, en el primer caso estás usando ( ) para envolver el objeto que deseas ejecutar con el siguiente conjunto de () , y en el siguiente caso estás usando un operador que toma un argumento (¡operador de negación!) Y lo estás haciendo implícitamente envuelva su argumento (función) con ( ) para que realmente obtenga !(function () { })() , ejecute la función y anule el resultado que devuelve. Esto también puede funcionar con -, +, ~ en el mismo principio ya que todos esos operadores toman un argumento.

!function () { /* presumably the same magic happens */ }() -function () { /* presumably the same magic happens */ }() +function () { /* presumably the same magic happens */ }() ~function () { /* presumably the same magic happens */ }()

Por qué querrías hacer esto? Supongo que es una preferencia personal o si tienes un .JS grande y quieres guardar 1 char por llamada de función anónima ...: D

Posible duplicado:
¿Qué hace el signo de exclamación antes de la función?

Durante mucho tiempo he usado lo siguiente para funciones anónimas autoejecutables en JavaScript:

(function () { /* magic happens */ })()

Últimamente, he comenzado a ver más instancias del siguiente patrón (por ejemplo, en Bootstrap ):

!function () { /* presumably the same magic happens */ }()

Alguien sabe cuál es la ventaja del segundo patrón? O, ¿es solo una preferencia estilística?


El primer "patrón" llama a la función anónima (y tiene el resultado de su valor de retorno) mientras que el segundo llama a la función anónima y niega su resultado.

¿Es eso lo que estás preguntando? Ellos no hacen lo mismo.


Es casi una preferencia estilística, ¡excepto por el hecho de que ! proporciona un retorno de función (es decir, devuelve true , que viene de !undefined ).

Además, es un personaje menos.


Estas dos técnicas diferentes tienen una difference funcional, así como una diferencia en apariencia. Las ventajas potenciales de una técnica sobre la otra se deben a estas diferencias.

Corte

Javascript es un lenguaje donde la concisión puede ser muy importante, porque Javascript se descarga cuando se carga la página . Eso significa que cuanto más conciso es el Javascript, más rápido es el tiempo de descarga . Por este motivo, existen minifiers y obfuscators Javascript que comprimen los archivos Javascript para optimizar el tiempo de descarga. Por ejemplo, los espacios en alert ( "Hi" ) ; sería optimizado para alert("Hi"); .

Teniendo esto en cuenta, compara estos dos patrones

  • closure normal : (function(){})() 16 caracteres
  • Cierre Negated !function(){}() 15 caracteres

Esto es una micro-optimización en el mejor de los casos, así que no creo que este sea un argumento particularmente convincente a menos que esté haciendo un concurso de golf de código .

Negando el valor devuelto

Compare el valor del resultado de b .

var a = (function(){})() var b = !function(){}()

Como la función a no devuelve nada, a no estará undefined . Como la negación de undefined es true , b evaluará a true . Esta es una ventaja para las personas que desean negar el valor devuelto de la función o tener un fetiche de todo-debe-devolver-un-no-nulo-o-valor-indefinido. Puede ver una explicación de cómo funciona esto en esta otra pregunta de Desbordamiento de pila.

Espero que esto te ayude a comprender la lógica detrás de esta declaración de función que normalmente se consideraría un anti-pattern .


Parece que la clave es que básicamente se trata de evitar que el analizador interprete la función como una declaración de función, y en su lugar se interpreta como una expresión de función anónima.

Usando los parens para agrupar la expresión o usar el! negar el retorno son ambas técnicas para cambiar el análisis sintáctico. Luego es invocado inmediatamente por los siguientes parientes. Todos y cada uno de estos formularios tienen el mismo efecto neto en ese sentido, suponiendo que no hay un valor de retorno explícito:

(function(){ /* ... */ })(); // Arguably most common form, => undefined (function(){ /* ... */ }()); // Crockford-approved version, => undefined !function(){ /* ... */ }(); // Negates the return, so => true +function(){ /* ... */ }(); // Attempts numeric conversion of undefined, => NaN ~function(){ /* ... */ }(); // Bitwise NOT, => -1

Si no está capturando el valor devuelto, no hay una diferencia significativa. Se podría argumentar que la ~ podría ser una operación más rápida, ya que solo se trata de una inversión de bits, ¡o tal vez! es una operación más rápida ya que es una verificación de verdadero / falso y devuelve la negación.

Sin embargo, al final del día, la forma en que la mayoría de la gente usa este patrón es que están tratando de romper un nuevo nivel de alcance para mantener las cosas limpias. Cualquiera y todo el trabajo. Las últimas formas son populares porque si bien introducen una operación adicional (generalmente innecesaria), guardar cada byte adicional ayuda.

Ben Alman tiene una fantástica reseña sobre el tema: http://benalman.com/news/2010/11/immediately-invoked-function-expression/


Siempre recurro a la pieza IIFE de Ben Alman para preguntas como esta. Es lo definitivo en lo que a mí respecta.

Aquí está la carne del artículo :

// Either of the following two patterns can be used to immediately invoke // a function expression, utilizing the function''s execution context to // create "privacy." (function(){ /* code */ }()); // Crockford recommends this one (function(){ /* code */ })(); // But this one works just as well // Because the point of the parens or coercing operators is to disambiguate // between function expressions and function declarations, they can be // omitted when the parser already expects an expression (but please see the // "important note" below). var i = function(){ return 10; }(); true && function(){ /* code */ }(); 0, function(){ /* code */ }(); // If you don''t care about the return value, or the possibility of making // your code slightly harder to read, you can save a byte by just prefixing // the function with a unary operator. !function(){ /* code */ }(); ~function(){ /* code */ }(); -function(){ /* code */ }(); +function(){ /* code */ }(); // Here''s another variation, from @kuvos - I''m not sure of the performance // implications, if any, of using the `new` keyword, but it works. // http://twitter.com/kuvos/status/18209252090847232 new function(){ /* code */ } new function(){ /* code */ }() // Only need parens if passing arguments