2011-12-12 17 views
5

me encontré con el siguiente patrón cuando se mira a través del código fuente SlickGrid:¿Cuál es el motivo de este patrón de invocación inmediata de JavaScript?

(function ($) { 
    var SlickEditor = { 

    TextCellEditor: function (args) { 
     ... 
    }, 

    LongTextCellEditor: function (args) { 
     ... 
    } 
    }; 

    $.extend(window, SlickEditor); 

})(jQuery); 

Si entiendo esto correctamente, se está utilizando la invocación inmediata para definir varios objetos de función y luego unirlos en el espacio de nombres global.

Así que podría definir mis funciones globalmente así y tendría el mismo efecto, ¿no?

function TextCellEditor (args) { 
    ... 
} 

function LongTextCellEditor (args) { 
    ... 
} 

La única diferencia que puedo ver es que en la primera versión, puedo usar la taquigrafía $ para referirse al objeto jQuery. Aparte de eso, el resultado sería idéntico en ambos casos.

Me gustaría saber si me falta algo. Tal vez hay otra buena razón para hacer las cosas de esta manera?

ACTUALIZACIÓN: Tenga en cuenta que el uso de este patrón de invocación inmediata permite el uso de variables privadas declaradas en la función anónima. Pero no hay ninguna variable declarada en este caso y las funciones se están inyectando en el alcance global de todos modos. Así que aún me gustaría saber si hay alguna diferencia real.

Algunas respuestas señalaron que hacer referencia a variables locales es mucho más rápido que hacer referencia a variables globales. ¿Esto sigue siendo cierto si hago referencia al $ desde el constructor TextCellEditor()? $ no es realmente local en TextCellEditor() ya que está definido en el ámbito de la función anónima externa.

Todos los comentarios apreciados.

+0

... El ejemplo que se muestra inyecta una sola variable en el alcance global. Usted inyecta múltiples funciones en el alcance global. Hay una enorme diferencia entre una variable global y muchas variables globales – Raynos

+0

@Raynos: ambos ejemplos inyectan las mismas funciones en el alcance global. la llamada '$ .extend()' amplía el objeto de ventana con todas las propiedades de 'SlickEditor' (en este caso, las dos funciones de constructor). Ese es el punto de mi pregunta: ¿cuál es la diferencia? – njr101

+0

oh, espera, no me di cuenta de que el autor de SlickEditor era un idiota e inyectó todas las funciones en el alcance global. Es un patrón anti, ambos ejemplos de código son malas prácticas. – Raynos

Respuesta

3

La diferencia es que está creando un alcance local para variables privadas cuando usa una función de invocación automática como la que ha mostrado.

Ese tipo de función de auto invocación generalmente se llama un cierre y es la base de muchos patrones de javascript como el patrón módulo: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

Usted puede leer más acerca de Javascript de alcance aquí: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

La razón de pasando el vairable jQuery es en 2 partes:

1: es más conveniente llamarlo a través $ y ya que se pasa como una variable local podemos estar seguros de que $ no es otra cosa

2: es más rápido - Las variables locales son mucho más rápido para acceder y trabajar con que las variables globales

Como ejemplo echar un vistazo a la siguiente trozo de código:

var public_and_global=true; 

(function(){ 
    var private_and_local = true; 

    function local_func() { 
    //can use private_and_local as well as public_and_global 
    } 

})(); 

function global_func() { 
    //can only use public_and_global 
} 
+0

No hay variables "privadas" – Raynos

+0

Gracias Martin. Entiendo el problema del alcance/cierre. Pero dado que no hay variables en la función anónima, pensé que esto significaría que el resultado neto sería el mismo en ambos ejemplos. No estaba al tanto de la diferencia de rendimiento. ¿El beneficio de rendimiento se aplica al uso de '$' dentro del constructor TextCellEditor? No estoy seguro porque '$' no es realmente local para esa función, sino local para la función anónima en el ámbito externo. – njr101

+0

Tiene razón, en su ejemplo exacto, el resultado neto está muy cerca de ser el mismo, a excepción de las dos funciones en el primer ejemplo que están dentro del espacio de nombres 'SlickEditor'. El clima o no es una diferencia de rendimiento en el escenario exacto es algo que dejaré a su prueba :) –

0

Sí, tendría la mismo efecto, en la mayoría de los casos. Pero de esta manera es bueno porque siempre puedes usar la taquigrafía, pero también porque no habrá variables que abarroten el espacio de nombres global.Decir que tengo esta extensión, para generar identificadores únicos:

var UID = (new Date).getTime(); 
$.uniqueID = function() { return (UID++).toString(16); } 

Esto sería sólo el trabajo, pero si fijo UID más tarde, probablemente en otro script, esta función no funcionará más. Y bueno, nunca se puede estar tan seguro de la disponibilidad de $, que es una buena razón, también.

Las variables definidas dentro de una función no existirán en el espacio de nombres global.

1

Todo el mundo envuelve su código completo en un IIFE.

Esto se debe a que todos usan variables locales y nadie usa variables globales.

Si su técnica de arquitectura modular pasa a ser "Inyectar módulos en el alcance global", inyectará módulos en el alcance global de su IIFE.

+0

+1 para influir en los desarrolladores con * "Todos lo hacen ..." * presión de grupo. – RightSaidFred

+0

Gracias por el consejo.Soy consciente de las mejores prácticas en esta situación, pero esperaba una respuesta a mi pregunta específica. – njr101

0

Definitivamente, lo que dijo Martin. También:

Así que podría simplemente definir mis funciones globalmente así y sería tener el mismo efecto, ¿verdad?

No. Esas funciones no terminan en el espacio de nombres global. Se están creando en un ámbito local, y luego se le dan referencias a jQuery. Nada se agrega al alcance global.

Aunque el fragmento que mostró no lo demuestra, es posible definir algunos datos privados, además de las funciones, dentro de ese ámbito, por ejemplo, cadenas fijas o tablas de búsqueda, o cualquier información auxiliar que esos métodos puedan necesitar, y las funciones tendrán acceso a esos datos, y aún así esos datos no serán accesibles para ningún otro código (análogo a "privado" en OO), ni esos datos contaminarán el espacio de nombre global.

+0

No entiendo esto. Seguramente la línea '$ .extend (window, SlickEditor);' extenderá el objeto global (en el caso de un navegador es el objeto ventana). Esas funciones estarán disponibles para cualquier línea de código, sin dependencia de jQuery. – njr101

Cuestiones relacionadas