Использование самоисполняющихся анонимных функций внутри шаблона раскрывающегося модуля

#javascript #design-patterns #iife

#javascript #шаблоны проектирования #iife

Вопрос:

Просто хотел узнать, было ли это хорошей практикой JavaScript.

Допустим, у меня есть много веб-страниц, которые все вызывают функцию инициализации «init ()», было бы правильно использовать IIFE внутри моего шаблона для запуска функции при каждой загрузке скрипта?

 var foo = (function() {
    var bar = "something";

    (function init() {
        // Do something crazy that's gonna be the same across all my web pages
        // like adding an event listener or something
        // ...
        document.write('page init...');
    }());

    function privatePage1() {
        // This stuff is gonna be used only in page1.html via foo.privatePage1
        document.write('page 1'   bar);
    }

    function privatePage2() {
        // This stuff is gonna be used only in page2.html via foo.privatePage2
        document.write('page 2'   bar);
    }

    return {
        privatePage1: privatePage1,
        privatePage2: privatePage2
    }
}());
  

Комментарии:

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

Ответ №1:

Это довольно субъективная область, но вот мое мнение:

  • Когда вы используете шаблон модуля, вы предоставляете ограниченный набор функций остальной части вашего кода. По сути, это мини-библиотека.

  • В общем, я бы не ожидал, что библиотека будет что-либо делать при ее загрузке, кроме шагов инициализации, которые полностью являются внутренними для библиотеки (например, настройка конфигурации, создание нескольких необходимых объектов и т. Д.) — Ничего, что действительно влияет на DOM или иным образом существенно изменяет среду (вот почемуЯ никогда не был полностью доволен такими библиотеками, как Date.js или Прототип, который изменяет прототипы базовых объектов).

  • Для этого есть несколько причин, но главная из них заключается в том, что я не хочу беспокоиться о порядке загрузки моих библиотек / модулей, кроме простого управления зависимостями. Независимые модули вообще не должны влиять друг на друга. Когда вы манипулируете DOM в своем модуле во время загрузки, рано или поздно вы поймете, что другая часть вашего кода ожидает, что DOM будет находиться в определенном состоянии в определенное время, и что теперь вам нужно заботиться о том, загружаете ли вы свой модуль до или после этого времени. Это дополнительная сложность, которая, по сути, скрыта в теге script, который загружает ваш модуль.

  • Другой проблемой здесь является переносимость и адаптивность. Возможно, вы захотите использовать свой модуль в другом проекте с другой настройкой DOM. Возможно, вы захотите передать другой элемент DOM или переменную конфигурации init() функции на определенной странице. Если вы выполняете init() автоматически, вы теряете возможность настройки.

Итак, что я обычно делаю, так это устанавливаю init() метод в качестве атрибута возвращаемого объекта модуля:

 var foo = (function() {

    function init() {
        // Do something crazy that's gonna be the same across all my web pages
    }

    //...

    return {
        init: init,
        // etc
    }
}());
  

а затем вызывайте его по мере необходимости в другом месте моего кода:

 foo.init();
  

Да, это добавляет дополнительную строку избыточного кода к инициализации для всех моих страниц (хотя в любом случае это, вероятно, всего лишь один другой скрипт, поэтому добавленный вес составляет всего 11 символов). Но это позволяет мне более точно контролировать, когда модуль инициализируется, и предлагает перехват для аргументов конфигурации, когда я (неизбежно) определю, что они мне понадобятся позже.

Комментарии:

1. Очень хороший ответ. Прямо сейчас я также возвращал функцию init(), но задавался вопросом, могу ли я сэкономить дополнительный шаг ее вызова на каждой странице. Ваши аргументы имеют идеальное значение!

2. Я действительно ценю ваш комментарий о том, что модуль ничего не делает при загрузке. Я пишу свой первый в истории настоящий модуль js, и мне было поручено использовать «раскрывающий модуль», в данном случае это скорее «скрывающий модуль», поскольку без an init ему действительно не нужно ничего раскрывать. Ваше предложение init дало мне хороший старт.

Ответ №2:

Одинакова ли эта init() функция на всех веб-страницах? Если да, то это то, что я бы сделал:

 var foo = (function()
{
    init();
    return {};
}());
  

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

 var foo = (function()
{
    /* body of the original IIFE here */
    return {};
}());