2011-02-16 6 views
53

Supongo que usar este patrón es el nuevo picor, pero no entiendo cuál es la ventaja y no entiendo las implicaciones del alcance.¿Qué ventajas otorga el uso (función (ventana, documento, indefinido) {...}) (ventana, documento)?

El patrón:

(function(window, document, undefined){ 
    window.MyObject = { 
    methodA: function() { ... }, 
    methodB: function() { ... } 
    }; 
})(window, document) 

así que tengo varias preguntas sobre esto.

¿Hay alguna ventaja especial en encapsular un objeto como este?
¿Por qué se alimenta ventana y documento en lugar de solo acceder a ella normalmente?
¿Por qué diablos está pasando undefined?
¿Es una buena idea asociar el objeto que estamos creando directamente a la ventana?

Estoy acostumbrado a lo que llamaré el estilo de Crockford de la encapsulación de Javascript (porque lo saqué de los videos de Douglas Crockford Javascript).

NameSpace.MyObject = function() { 
    // Private methods 
    // These methods are available in the closure 
    // but are not exposed outside the object we'll be returning. 
    var methodA = function() { ... }; 

    // Public methods 
    // We return an object that uses our private functions, 
    // but only exposes the interface we want to be available. 
    return { 

    methodB: function() { 
     var a = methodA(); 
    }, 
    methodC: function() { ... } 

    } 
// Note that we're executing the function here. 
}(); 

¿Uno de estos patrones es funcionalmente mejor que el otro? ¿El primero es una evolución del otro?

+0

respuesta en dos palabras: almacenamiento en caché + espacio aislado; para más detalles, consulte a continuación;) – Christoph

+1

Consulte también [¿Cómo funciona esta sintaxis JavaScript/JQuery: (función (ventana, indefinido) {}) (ventana)?] (http://stackoverflow.com/questions/2716069/how- does-this-javascript-jquery-syntax-work-function-window-undefined) – Bergi

Respuesta

46

¿Por qué se alimenta la ventana y el documento en lugar de solo acceder a él normalmente?

Generalmente para ajustar el proceso de resolución de identificador, tenerlos como variables locales puede ayudar (aunque IMO las mejoras de rendimiento pueden ser insignificantes).

Pasando el objeto global es también una técnica ampliamente utilizada en entornos que no sean de navegador, en el que no tiene un identificador window en el ámbito global, por ejemplo:

(function (global) { 
    //.. 
})(this); // this on the global execution context is 
      // the global object itself 

¿Por qué diablos no está definido siendo pasado?

Esto es debido a que el undefined propiedad global en ECMAScript 3, es mutable, lo que significa que alguien podría cambiar su valor afecta a su código, por ejemplo:

undefined = true; // mutable 
(function (undefined) { 
    alert(typeof undefined); // "undefined", the local identifier 
})(); // <-- no value passed, undefined by default 

Si se fijan bien undefined no es en realidad pasado (no hay argumento en la llamada a función), esa es una de las formas confiables de obtener el valor undefined, sin usar la propiedad window.undefined.

El nombre undefined en JavaScript no significa nada especial, no es una palabra clave como true, false, etc ..., es solo un identificador.

Sólo para que conste, en ECMAScript 5, esta propiedad se hizo no escrito ...

es unir el objeto que estamos creando directamente a la ventana de una idea especialmente buena?

Es una forma común utilizada para declarar propiedades globales cuando se encuentra en otro ámbito de función.

+1

¿Por qué pasar ventana y documento? ¿El documento no es una propiedad de la ventana? –

+2

@ShaunLuttin Simplemente hace que las referencias sean más rápidas. No solo eso, de esa manera puedes usarlo de la manera en que la mayoría de la gente está acostumbrada. Usualmente no lo usa como: window.document.whatever(), lo usa como: document.whatever(). Si no lo hace y hace "document.whatever()", en realidad, está utilizando el objeto de ventana global en lugar del ámbito, aunque no sea lo suficientemente claro. Últimamente, permite una mejor minimización. La ventana puede convertirse en "w" y documentar "d". Solo por eso puede reducir los guiones por una gran cantidad de caracteres. – brunoais

1

Estoy contigo en el uso del estilo de Crockford.

para responder a sus preguntas

1.Is existe una ventaja particular para encapsular un objeto como éste?

La única ventaja que puedo ver es haciendo variables locales de ventana y documento en lugar de variables globales, se obtiene un mayor nivel de seguridad al no poder sobreescribir ninguna de las dos y la ganancia de rendimiento es local.

2.¿Por qué se están alimentando la ventana y el documento en lugar de simplemente acceder a él normalmente?

Dirigido arriba. Las variables locales tienden a ser más rápidas, pero con jit compilar en estos días eso se está convirtiendo en nominal.

3.¿Por qué diablos no se ha definido?

Ninguna pista ....

4.Is fijar el objeto que estamos creando directamente a la ventana de una idea especialmente buena?

Probablemente no, pero aún me quedaría con el patrón de Crockford ya que asociar la función al objeto ventana lo expone al resto de la pila global a través del objeto ventana en lugar de exponerlo a través de un espacio de nombres no estándar.

+2

Creo que el motivo indefinido se pasa porque ES teóricamente posible sobrescribir indefinido (es decir, no es realmente una palabra clave en algunas implementaciones, solo una variable global inicialmente no definida). Por lo tanto, proporciona un tercer parámetro, llamado "indefinido", y luego no pasa nada (lo que lo hace definitivamente indefinido) y luego evita que un chiflado defina lo indefinido globalmente. –

+0

nice, se olvidó de eso – joekarl

+0

-1 porque sugiere que la ventana y "la pila global" (¿alcance global?) Son diferentes. –

1

Creo que esto es principalmente para el código que debe ejecutarse en contextos de múltiples ventanas. Supongamos que tiene una aplicación compleja con muchos iframes y/o ventanas secundarias. Todos necesitan ejecutar el código en MyObject, pero solo quieres cargarlo una vez. Entonces lo carga en cualquier ventana/marco que elija, pero crea un MyObject para cada ventana/marco con referencias a la ventana y el documento correctos.

Tomando un argumento definido está tratando de proteger contra el hecho de que se puede cambiar sin definir: Respuesta

undefined = 3; 
alert(undefined); 

Sede de CMS acerca de cómo esto mejora la seguridad.

+2

No está pasando indefinido, solo está declarando un parámetro llamado undefined, y no está pasando nada por ese parámetro, lo que lo hace realmente indefinido. Sin embargo, no estoy seguro de por qué es preferible a "var undefined" en la función. –

26

Este estilo particular tiene algunas ventajas sobre el estilo "Crockford". En primer lugar, al pasar window y document, se puede minimizar de manera más eficiente el script. Un minificador puede cambiar el nombre de esos parámetros a nombres de un solo carácter, ahorrando 5 y 7 bytes respectivamente por referencia. Esto puede sumarse: jQuery hace referencia a window 33 veces y document 91 veces. La reducción de cada token a un carácter ahorra 802 bytes.

Además, usted haga obtenga un beneficio de velocidad de ejecución. Cuando leí por primera vez la afirmación de @joekarl de que proporciona un beneficio de rendimiento, pensé, "eso parece bastante espurio". Así que perfilé el rendimiento real con un test page. Haciendo referencia a windowcien millones veces, la referencia de variable local proporciona un modesto aumento del 20% de velocidad (4200 ms a 3400ms) en Firefox 3.6 y un impactante aumento del 31,000% (13 segundos a 400ms) en Chrome 9.

Por supuesto, nunca va a hacer referencia a window 100,000,000 veces en la práctica, e incluso 10,000 referencias directas solo toman 1ms en Chrome, por lo que la ganancia de rendimiento real aquí es casi completamente insignificante.

¿Por qué diablos está pasando undefined?

Porque (como se menciona por @CMS) el token undefined is actually undefined. A diferencia de null, no tiene ningún significado especial, y puede asignar este identificador como cualquier otro nombre de variable. (Tenga en cuenta, sin embargo, que esto es no longer true in ECMAScript 5.)

¿Es una buena idea asociar el objeto que estamos creando directamente a la ventana?

El objeto window es el alcance global, por lo que es exactamente lo que está haciendo en algún momento, ya sea o no que explícitamente se escribe "ventana". window.Namespace = {}; y Namespace = {}; son equivalentes.

+3

+1 para ventaja de minificación – Sprintstar

+1

No olvide 'undefined' - un minificador también cambiará el nombre de este parámetro a un nombre corto, así como a todas las referencias en el script. –

Cuestiones relacionadas