Я поддерживаю унаследованный код и заметил, что для определения объектов используется следующий шаблон:
var MyObject = {};
(function (root) {
root.myFunction = function (foo) {
//do something
};
})(MyObject);
Есть ли в этом какая-то цель? Это эквивалентно простому выполнению следующего?
var MyObject = {
myFunction : function (foo) {
//do something
};
};
Я не собираюсь пускаться в священный квест по рефакторингу всей кодовой базы по своему вкусу, но мне действительно хотелось бы понять причину такого окольного способа определения объектов.
Благодарность!
javascript
javascript-objects
Себастьян Ванстенкисте
источник
источник
myFunction
может использовать некоторые переменные, определенные вне себя, которые не будут доступны извне. Смотрите мой ответОтветы:
Это называется модульным шаблоном http://toddmotto.com/mastering-the-module-pattern/
Основная причина заключается в том, чтобы вы создавали по-настоящему частные методы и переменные. В вашем случае это не имеет смысла, потому что не скрывает никаких деталей реализации.
Вот пример, в котором имеет смысл использовать шаблон модуля.
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
Если бы вы просто использовали прямой объект
adder
иvalue
стали бы общедоступнымиvar MyNameSpace = { value: 0, adder: function(num) { return num + 1; }, getNext: function() { return this.value = this.adder(this.value); } }
И вы можете сломать его, сделав что-то вроде
MyNameSpace.getNext(); // 1 MyNameSpace.value = 0; MyNameSpace.getNext(); // 1 again delete MyNameSpace.adder; MyNameSpace.getNext(); // error undefined is not a function
Но с версией модуля
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
источник
ns.getNext: function () {
не скомпилируется.delete MyNameSpace.getNext
.:)
Цель состоит в том, чтобы ограничить доступность функций в закрытии, чтобы предотвратить выполнение кода другими скриптами . Оборачивая его вокруг замыкания, вы переопределяете объем выполнения для всего кода внутри замыкания и эффективно создаете частную область. См. Эту статью для получения дополнительной информации:
http://lupomontero.com/using-javascript-closures-to-create-private-scopes/
Из статьи:
Код:
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
источник
myFunction
не входит в глобальную область видимости во второй версии. На самом деле цель состоит в том, чтобы предоставить область, в которой могут быть определены внутренние вспомогательные функции.myFunction
находится в глобальной области видимости, поскольку определен в глобальном объектеmyObject
. Во второй версии мог выполняться любой другой код в приложенииmyFunction
. В первой версии только код в закрытии имеет доступ кmyFunction
myFunction
может выполняться только какMyObject.myFunction()
, как и в первой версии.преимущества:
поддерживает переменные в частной области.
вы можете расширить функционал существующего объекта.
производительность повышена.
Я думаю, что трех приведенных выше простых пунктов достаточно, чтобы следовать этим правилам. И для простоты - ничего, кроме написания внутренних функций.
источник
В конкретном случае, который вы показываете, нет значимой разницы с точки зрения функциональности или видимости.
Вполне вероятно, что исходный кодировщик принял этот подход как своего рода шаблон, позволяющий ему определять частные переменные, которые можно было бы использовать в определении таких вещей, как
myFunction
:var MyObject = {}; (function(root) { var seconds_per_day = 24 * 60 * 60; // <-- private variable root.myFunction = function(foo) { return seconds_per_day; }; })(MyObject);
Это позволяет избежать вычислений
seconds_per_day
каждый раз при вызове функции, а также не допустить загрязнения глобальной области видимости.Тем не менее, нет ничего принципиально отличного от этого и просто говорю
var MyObject = function() { var seconds_per_day = 24 * 60 * 60; return { myFunction: function(foo) { return seconds_per_day; } }; }();
Первоначальный кодировщик, возможно, предпочел иметь возможность добавлять функции к объекту, используя декларативный синтаксис
root.myFunction = function
, а не синтаксис объекта / свойстваmyFunction: function
. Но это различие в основном вопрос предпочтений.Однако структура, принятая исходным кодировщиком, имеет то преимущество, что свойства / методы могут быть легко добавлены в другом месте кода:
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);
В итоге, нет необходимости применять этот подход, если он вам не нужен, но также нет необходимости его менять, поскольку он отлично работает и на самом деле имеет некоторые преимущества.
источник
Первый шаблон можно использовать как модуль, который принимает объект и возвращает этот объект с некоторыми изменениями. Другими словами, вы можете определить такие модули следующим образом.
var module = function (root) { root.myFunction = function (foo) { //do something }; }
И используйте это так:
var obj = {}; module(obj);
Таким образом, преимуществом может быть возможность повторного использования этого модуля для дальнейшего использования.
В первом шаблоне вы можете определить частную область для хранения ваших личных вещей, таких как частные свойства и методы. Например, рассмотрим этот фрагмент:
(function (root) { // A private property var factor = 3; root.multiply = function (foo) { return foo * factor; }; })(MyObject);
Этот шаблон можно использовать для добавления метода или свойства ко всем типам объектов, таким как массивы, объектные литералы, функции.
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
На мой взгляд, главным преимуществом может быть второе (создание частной области видимости).
источник
Этот шаблон предоставляет область видимости, в которой вы можете определять вспомогательные функции, которые не видны в глобальной области:
(function (root) { function doFoo() { ... }; root.myFunction = function (foo) { //do something doFoo(); //do something else }; })(MyObject);
doFoo
является локальным для анонимной функции, на него нельзя ссылаться извне.источник