Использует ли этот способ определения объектов 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 является локальным для анонимной функции, на него нельзя ссылаться извне.