2012-02-09 17 views
5

EDITARcierres de Javascript - ¿Cuál es la diferencia entre estos

Con el número de respuestas que dicen "usted puede hacer cosas particulares!" a continuación, voy a agregar esto a la parte superior también:

Sé que puede emular variables privadas dentro de un cierre. Eso no es lo que estoy preguntando. Estoy preguntando, dados los dos ejemplos a continuación donde estoy "exportando" TODO desde el cierre, ¿cuál es la diferencia fundamental entre estos dos ejemplos?

Teniendo en cuenta estos dos métodos de creación de objetos/métodos:

var test = {} 

test = (function(){ 
    var a_method = function(print_me){ 
     return "hello "+print_me; 
    } 

    return {print_me: a_method}; 
})(); 

test.print_me2 = function(print_me2){ 
    return "hello "+print_me2; 
} 

test.print_me('world'); 
>>> returns "hello world" 

test.print_me2('world'); 
>>> returns "hello world" 

entiendo que el primer método permite variables privadas (que como desarrollador de Python en el fondo no me importa usar), pero ambos parecen más bien equivalentes para mí, solo el primero parece "más fresco" (como en todos los grandes javascript, la gente parece hacerlo de esa manera) y el segundo parece muy pasado.

Entonces, ¿cuál es la diferencia?

He revisado las preguntas de cierre aquí - la mayoría se centran en qué o por qué las usa; Entiendo su utilidad, solo quiero saber por qué harías la primera sobre el segundo y qué beneficios tiene.

preferiría pruebas contundentes sobre la conjetura - no en busca de un "así es como los niños frescos lo están haciendo" o "he oído que Mozilla hace mejor uso de la memoria cuando se utiliza un cierre", pero la evidencia más cualitativa hacia uno siendo "mejor" que el otro.

Respuesta

3

La diferencia entre los métodos es la envoltura de función anónima que crea un cierre, pero también que el primer método reemplaza el objeto completo mientras que el segundo método simplemente establece una propiedad en el método existente.

Existen diferentes formas de agregar métodos a un objeto. Usted puede poner allí cuando se crea el objeto:

var test = { 
    print_me: function(text) { return "hello " + text; } 
}; 

Puede agregar un método como una propiedad de un objeto existente:

var test = {}; 
test.print_me = function(text) { return "hello " + text; }; 

se puede hacer una función constructora, y añadir métodos a su prototipo:

function Test() {} 
Test.prototype.print_me = function(text) { return "hello " + text; }; 
var test = new Test(); 

Como Javascript tiene un modelo de objetos basado en prototipos, la última es la forma en métodos estaban destinados a ser creado. Las otras formas son simplemente posibles porque una propiedad del objeto puede tener una función como valor.


Se puede utilizar un envoltorio de la función alrededor de cualquier código en el que desea variables locales, por lo que se puede hacer eso con la segunda forma de establecer la propiedad:

test.print_me2 = (function(){ 

    var method = function(print_me2) { 
    return "hello "+print_me2; 
    } 

    return method; 
})(); 
+0

es una respuesta mucho mejor que antes. Y sí, entiendo que estoy configurando el objeto para que sea el resultado de la función ejecutada inmediatamente en lugar de establecer una propiedad de dicho objeto; supongamos que estoy tratando de hacer simplemente 'print_me', que será la única propiedad en el objeto de prueba. ¿Cuáles serían los beneficios de hacerlo en un cierre en lugar de hacerlo como una tarea directa? – tkone

+0

@tkone: El beneficio de hacerlo en un cierre es solo que usted tiene el cierre. Puede crear variables locales para no contaminar el espacio de nombres global. Sin embargo, tener cuidado con el espacio de nombres global es más problemático si está escribiendo código de biblioteca o complementos. La gran biblioteca jQuery, por ejemplo, solo agrega dos nombres al espacio de nombres global. – Guffa

+0

ok cool. eso es exactamente lo que estaba tratando de descifrar. Sé que agregar una tonelada de nombres al espacio de nombres global es una mala idea (por lo tanto, usar espacios de nombres), pero solo quería saber si la gente estaba haciendo cierres porque están "calientes" o si sirvieron una utilidad en un caso como el anterior. – tkone

2

En el primer ejemplo, el cierre se utiliza para mantener las variables locales fuera del alcance global.

var thisIsGlobal = 2; 
var test = (function() { 
    var thisIsLocal = 3; 
    return function() { 
    return thisIsLocal; 
    }; 
}()); 

Lo que se obtiene es una función test que cuando se invoca devuelve el valor de la variable local thisIsLocal. No hay forma de cambiar el valor de la variable. Puedes verlo como una variable privada.

+1

realmente me gustaría Javascript tenía una mejor manera de hacer las cosas privadas privada ... –

+1

"de ninguna manera" no es del todo correcto. Algunos motores js (antiguos) permiten acceder al atributo '.__ parent__' de las funciones, que de hecho permitiría acceder a un ámbito primario cerrado. – jAndy

+0

@ JanKuča Entiendo los problemas del alcance aquí - lo que estoy preguntando no tiene nada que ver con privado/público o emulación del mismo, sino la diferencia entre los dos ejemplos: uno en un cierre que exporta TODO y uno fuera de un cierre . – tkone

0

El primer método que se presente (una función anónima que se ejecuta inmediatamente) mantiene su programa fuera del alcance global. Dentro de ese ámbito privado puede decidir qué propiedades desea exponer como su API:

(function(win){ 
    var a, b, c = 1; 

    function init(){ 
    return aa(b); 
    } 

    function exit(){ 
    if(cc()){ 
     return a; 
    } 
    } 

    function aa(){ 
    } 

    function bb(){ 
    } 

    function cc(){ 
    } 

    win.myProgram = {init: init, 
        exit: exit }; 
})(window); 


// We now have access to your API from within the global namespace:  
myProgram.init();  
//etc 
Cuestiones relacionadas