Использует ли этот способ определения объектов JS какую-либо цель?
Я поддерживаю некоторый унаследованный код, и я заметил, что используется следующий шаблон для определения объектов:
var MyObject = {};
(function (root) {
root.myFunction = function (foo) {
//do something
};
})(MyObject);
Есть ли какая-то цель? Это эквивалентно просто выполнению следующего?
var MyObject = {
myFunction : function (foo) {
//do something
};
};
Я не собираюсь вступать в священный квест, чтобы реорганизовать всю кодовую базу по своему вкусу, но мне бы очень хотелось понять причину этого обходного способа определения объектов.
Спасибо!
Ответы
Ответ 1
Он назвал шаблон модуля 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 creating a new property
MyNameSpace.value = 0;
MyNameSpace.getNext(); // 2, yessss
// Is not deleting anything
delete MyNameSpace.adder;
MyNameSpace.getNext(); // no problemo, outputs 3
Ответ 2
Цель состоит в том, чтобы ограничить доступность функций в закрытии, чтобы помочь другим скриптам выполнять код на нем. Обернувшись вокруг закрытия, вы переопределяете область выполнения для всего кода внутри закрытия и эффективно создаете закрытую область. См. Эту статью для получения дополнительной информации:
http://lupomontero.com/using-javascript-closures-to-create-private-scopes/
Из статьи:
Одной из наиболее известных проблем в JavaScript является ее зависимость от глобальный охват, что в основном означает, что любые переменные, которые вы заявляете вне функции живут в одном и том же пространстве имен: зловещий оконный объект. Из-за характера веб-страниц многие скрипты из различные источники могут (и будут) работать на одной и той же странице, общий глобальный масштаб, и это может быть действительно очень плохо, поскольку может привести к конфликтам имен (переменные с одинаковыми именами перезаписан) и проблемы с безопасностью. Чтобы свести к минимуму проблему, мы можем использовать Явные скрипты JavaScripts для создания частных областей, где мы можем убедитесь, что наши переменные невидимы для других скриптов на странице.
Код:
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
Ответ 3
В конкретном случае, который вы показываете, нет существенной разницы в плане функциональности или видимости.
Вероятно, исходный кодер принял этот подход как своего рода шаблон, позволяющий ему определять частные переменные, которые можно было бы использовать в определении таких вещей, как 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);
Итог, нет необходимости применять этот подход, если вам это не нужно, но нет необходимости его изменять, так как он отлично работает и на самом деле имеет некоторые преимущества.
Ответ 4
Adavtages:
1. Первый шаблон может использоваться как модуль, который принимает объект и возвращает этот объект с некоторой модификацией. Другими словами, вы можете определить такой модуль следующим образом:
var module = function (root) {
root.myFunction = function (foo) {
//do something
};
}
И используйте его как:
var obj = {};
module(obj);
Таким образом, преимущество может быть в том, что этот модуль можно использовать повторно для последующего использования.
2. В первом шаблоне, как уже упоминалось ранее, вы можете определить частную область для хранения ваших личных вещей, таких как частные свойства и методы. Например, рассмотрите эти коды фрагментов
(function (root) {
// this plays as a private property
var factor = 3;
root.multiply = function (foo) {
return foo * factor;
};
})(MyObject);
3. Другим преимуществом может быть этот шаблон, который можно использовать для добавления метода или свойства ко всем типам объектов, таких как массивы, литералы, функции
function sum(a, b){
return a + b;
}
(function (root) {
// this plays as 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
Примечание. На мой взгляд, основным преимуществом может быть второй (создание частного поля)
Ответ 5
преимущества:
-
поддерживает переменные в частной области.
-
вы можете расширить функциональность существующего объекта.
-
увеличена производительность.
Я думаю, что три простых простых пункта достаточно, чтобы следовать этим правилам. И держать его просто, ничего, кроме написания внутренних функций.
Ответ 6
Этот шаблон предоставляет область, в которой вы можете определить вспомогательные функции, которые не видны в глобальной области:
(function (root) {
function doFoo() { ... };
root.myFunction = function (foo) {
//do something
doFoo();
//do something else
};
})(MyObject);
doFoo
является локальным для анонимной функции, на него нельзя ссылаться извне.