Mantengo un código heredado y he notado que se usa el siguiente patrón para definir objetos:
var MyObject = {};
(function (root) {
root.myFunction = function (foo) {
//do something
};
})(MyObject);
¿Tiene algún propósito esto? ¿Es equivalente a hacer lo siguiente?
var MyObject = {
myFunction : function (foo) {
//do something
};
};
No estoy a punto de embarcarme en una búsqueda sagrada para refactorizar todo el código base a mi gusto, pero realmente me gustaría entender la razón detrás de esa forma indirecta de definir objetos.
¡Gracias!
javascript
javascript-objects
Sebastián Vansteenkiste
fuente
fuente
myFunction
podría utilizar algunas variables definidas fuera de sí mismo que no serían accesibles desde el exterior. Ver mi respuestaRespuestas:
Se llama patrón de módulo http://toddmotto.com/mastering-the-module-pattern/
La razón principal es que cree métodos y variables verdaderamente privados. En su caso, no tiene sentido porque no oculta ningún detalle de implementación.
Aquí hay un ejemplo en el que tiene sentido utilizar el patrón de módulo.
var MyNameSpace = {}; (function(ns){ // The value variable is hidden from the outside world var value = 0; // So is this function function adder(num) { return num + 1; } ns.getNext = function () { return value = adder(value); } })(MyNameSpace); var id = MyNameSpace.getNext(); // 1 var otherId = MyNameSpace.getNext(); // 2 var otherId = MyNameSpace.getNext(); // 3
Mientras que si solo usara un objeto recto
adder
yvalue
se hiciera públicovar MyNameSpace = { value: 0, adder: function(num) { return num + 1; }, getNext: function() { return this.value = this.adder(this.value); } }
Y podrías romperlo haciendo cosas como
MyNameSpace.getNext(); // 1 MyNameSpace.value = 0; MyNameSpace.getNext(); // 1 again delete MyNameSpace.adder; MyNameSpace.getNext(); // error undefined is not a function
Pero con la versión del módulo
MyNameSpace.getNext(); // 1 // Is not affecting the internal value, it's creating a new property MyNameSpace.value = 0; MyNameSpace.getNext(); // 2, yessss // Is not deleting anything delete MyNameSpace.adder; MyNameSpace.getNext(); // no problemo, outputs 3
fuente
ns.getNext: function () {
no se compilará.delete MyNameSpace.getNext
.:)
El propósito es limitar la accesibilidad de las funciones dentro del cierre para ayudar a evitar que otros scripts ejecuten código en él. Al envolverlo alrededor de un cierre , está redefiniendo el alcance de ejecución de todo el código dentro del cierre y creando efectivamente un alcance privado. Consulte este artículo para obtener más información:
http://lupomontero.com/using-javascript-closures-to-create-private-scopes/
Del artículo:
Código:
var MyObject = {}; (function (root) { function myPrivateFunction() { return "I can only be called from within the closure"; } root.myFunction = function (foo) { //do something }; myPrivateFunction(); // returns "I can only be called from within the closure" })(MyObject); myPrivateFunction(); // throws error - undefined is not a function
fuente
myFunction
no está en el alcance global en la segunda versión. En realidad, el propósito es proporcionar un ámbito en el que se puedan definir funciones auxiliares internas.myFunction
está en el ámbito global porque está definido dentro del objeto globalmyObject
. En la segunda versión se podía ejecutar cualquier otro código de la aplicaciónmyFunction
. En la primera versión, solo el código dentro del cierre tiene acceso amyFunction
myFunction
solo se puede ejecutar comoMyObject.myFunction()
, igual que la primera versión.ventajas:
mantiene variables en ámbito privado.
puede ampliar la funcionalidad del objeto existente.
aumenta el rendimiento.
Creo que los tres simples puntos anteriores son suficientes para seguir esas reglas. Y para mantenerlo simple, no es más que escribir funciones internas.
fuente
En el caso particular que muestra, no hay una diferencia significativa, en términos de funcionalidad o visibilidad.
Es probable que el codificador original adoptó este enfoque como una especie de plantilla que le permite definir variables privadas que podrían usarse en la definición de cosas como
myFunction
:var MyObject = {}; (function(root) { var seconds_per_day = 24 * 60 * 60; // <-- private variable root.myFunction = function(foo) { return seconds_per_day; }; })(MyObject);
Esto evita calcular
seconds_per_day
cada vez que se llama a la función, al mismo tiempo que evita que contamine el alcance global.Sin embargo, no hay nada esencialmente diferente de eso y solo decir
var MyObject = function() { var seconds_per_day = 24 * 60 * 60; return { myFunction: function(foo) { return seconds_per_day; } }; }();
El codificador original puede haber preferido poder agregar funciones al objeto usando la sintaxis declarativa de
root.myFunction = function
, en lugar de la sintaxis de objeto / propiedad demyFunction: function
. Pero esa diferencia es principalmente una cuestión de preferencia.Sin embargo, la estructura adoptada por el codificador original tiene la ventaja de que las propiedades / métodos se pueden agregar fácilmente en otra parte del código:
var MyObject = {}; (function(root) { var seconds_per_day = 24 * 60 * 60; root.myFunction = function(foo) { return seconds_per_day; }; })(MyObject); (function(root) { var another_private_variable = Math.pi; root.myFunction2 = function(bar) { }; })(MyObject);
En resumen, no es necesario adoptar este enfoque si no es necesario, pero tampoco es necesario cambiarlo, ya que funciona perfectamente bien y en realidad tiene algunas ventajas.
fuente
El primer patrón se puede usar como un módulo que toma un objeto y lo devuelve con algunas modificaciones. En otras palabras, puede definir dichos módulos de la siguiente manera.
var module = function (root) { root.myFunction = function (foo) { //do something }; }
Y utilícelo como:
var obj = {}; module(obj);
Entonces, una ventaja podría ser la reutilización de este módulo para usos posteriores.
En el primer patrón, puede definir un ámbito privado para almacenar sus cosas privadas, como propiedades y métodos privados. Por ejemplo, considere este fragmento:
(function (root) { // A private property var factor = 3; root.multiply = function (foo) { return foo * factor; }; })(MyObject);
Este patrón se puede usar para agregar un método o propiedad a todo tipo de objetos, como matrices, literales de objeto, funciones.
function sum(a, b) { return a + b; } (function (root) { // A private property var factor = 3; root.multiply = function (foo) { return foo * factor; }; })(sum); console.log(sum(1, 2)); // 3 console.log(sum.multiply(4)); // 12
En mi opinión, la principal ventaja podría ser la segunda (crear un ámbito privado)
fuente
Este patrón proporciona un ámbito en el que puede definir funciones auxiliares que no son visibles en el ámbito global:
(function (root) { function doFoo() { ... }; root.myFunction = function (foo) { //do something doFoo(); //do something else }; })(MyObject);
doFoo
es local a la función anónima, no se puede hacer referencia a ella desde fuera.fuente