Имеет ли этот способ определения объектов JS какую-либо цель?


Я поддерживаю некоторый устаревший код, и я заметил, что используется следующий шаблон для определения объектов:

var MyObject = {};

(function (root) {

    root.myFunction = function (foo) {
        //do something
    };

})(MyObject);

есть ли смысл в этом? Это эквивалентно просто делать следующее?

var MyObject = {

    myFunction : function (foo) {
        //do something
    };

};

Я не собираюсь вступать в священный поиск, чтобы рефакторинг всей кодовой базы на мои симпатии, но я действительно хотел бы понять причину этого Окольного способа определения объектов.

спасибо!

6 86

6 ответов:

это называется модуль pattern 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

цель состоит в том, чтобы ограничить доступность функции в закрытие, чтобы помочь предотвратить другие скрипты от выполнения кода на нем. Обернув его вокруг закрытие вы переиначивая scope выполнения для всего кода внутри закрытие и эффективно создает частную область. См. эту статью для получения дополнительной информации информация:

http://lupomontero.com/using-javascript-closures-to-create-private-scopes/

из статьи:

одной из наиболее известных проблем в JavaScript является его зависимость от a глобальном уровне, который в основном означает, что любые переменные, которые вы объявляете вне функции живут в том же пространстве имен: зловещий объект Window. Из-за характера веб-страниц, многие скрипты из разные источники могут (и будут) работать на той же странице обмена общий глобальный охват, и это может быть действительно очень плохо, как это может привести к коллизиям имен (переменные с одинаковыми именами перезаписано) и вопросы безопасности. Чтобы минимизировать проблему, мы можем использовать Мощные замыкания JavaScript для создания частных областей, где мы можем убедитесь, что наши переменные невидимы для других скриптов на экране. страница.



код:

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

плюсы:

  1. поддерживает переменные в отдельный объем.

  2. можно расширить функциональные возможности существующего объекта.

  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);

итог, нет необходимости принимать этот подход, если вам это не нужно, но также нет необходимости его менять, поскольку он отлично работает и на самом деле имеет некоторые преимущества.

  1. первый шаблон может быть использован в качестве модуля, который принимает объект и возвращает объект с некоторыми изменениями. Другими словами, вы можете определить такие модули следующим образом.

    var module = function (root) {
        root.myFunction = function (foo) {
            //do something
        };
    }
    

    и использовать его как:

    var obj = {};
    module(obj);
    

    так что преимущество может быть повторное использование этого модуля для последующего использования.


  1. в первом шаблоне вы можете определить закрытая область для хранения личных такие вещи, как частные свойства и методы. Например, рассмотрим этот фрагмент кода:

    (function (root) {
    
        // A private property
        var factor = 3;
    
        root.multiply = function (foo) {
            return foo * factor;
        };
    })(MyObject);
    

  1. этот шаблон можно использовать для добавления метода или свойства ко всем типам объектов, таких как массивы, объектные литералы, функции.

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