Есть ли причина для определения module.exports с использованием IIFE?
У моей команды нет опытных разработчиков JS, но мы пишем библиотеку в Node и получили предложение от реального разработчика JS: "Мы должны сделать js более модульным - не загрязнять глобальное пространство имен и чтобы сделать его более читаемым для новичков", и сказал нам сделать следующее:
module.exports = (function(){
return {
nameToExpose: functionToExpose
...
};
})();
а не
module.exports.nameToExpose = functionToExpose;
В чем смысл этого, если таковой имеется? Последнее не делает никаких локальных заявлений, которые будут охвачены IIFE, и даже если бы это было так, они были бы локальными для файла модуля, а не глобальными для всей программы, которые require()
it.
Некоторые поисковые запросы и высказывание об этом сайте не дают ответов на этот конкретный вопрос, хотя есть много других объяснений IIFE, которые я прочитал (и которые обобщены в вышеупомянутом комментарии). Некоторое тестирование, безусловно, показывает, что последнее фактически не помещает functionToExpose
в глобальное пространство имен, хотя его исходное имя записывается в самом виде функции.
Ответы
Ответ 1
Совсем нет никакой разницы. Вся идея Node.js, использующая require
, имеющую модули и т.д., Специально предназначена для разделения проблем. Я бы сказал (осторожно), что, если вы делаете это правильно, вам не нужно беспокоиться о "загрязнении" любого глобального масштаба. Все, что находится внутри module.exports
, находится в этом модуле.
Когда вы имеете дело с интерфейсом, что когда глобальная область становится чем-то вроде проблемы, потому что, если функция или что-то не ограничено (т.е. в IIFE или другом функциональном блоке), она имеет доступ к глобальному объекту window
, а все остальное имеет доступ к этой функции.
реальный разработчик JS
Вызов кого-то, что является красным флагом.
не загрязнять глобальное пространство имен и сделать его более читаемым для новых пользователей
Если вы правильно модулируете свой код, это не должно вызывать беспокойства. Там время и место для IIFE, но я не вижу причин, по которым упаковка всего в IIFE, которая уже находится внутри модуля, каким-то образом волшебным образом сделает код "более модульным" или более читаемым для "новых посетителей", чем просто используя Node.js, как это было разработано:
module.exports = function() { ... } // whatever
и даже если бы это было так, они были бы локальны для файла модуля, а не глобальны для всей программы, что require()
it.
Вы правы. Я бы взял все, что он сказал, с солью. Возможно, он знает о некоторых конкретных случаях использования, когда его подход был полезным для него в прошлом, поэтому я бы спросил его конкретно об этом, чтобы увидеть, что он говорит. Помимо этого, я чувствую, что ты на правильном пути.
Ответ 2
Причина, пожалуй, иногда заключается в том, что если вы этого не сделаете, то любые переменные, которые вам нужны для объекта module.exports
, должны быть привязаны ко всему файлу.
Рассмотрим эти два пути.
-
Без IIFE.
var foo = 'la' + 'la'; // some computed value
//
// ... lots of program code here ...
//
module.exports = {
foo : foo,
};
-
С IIFE.
//
// ... lots of program code here ...
//
module.exports = (function () {
var foo = 'la' + 'la'; // some computed value
return {
foo : foo
}
}());
В первом примере возникают две проблемы.
- Ваши переменные (например,
foo
) создаются довольно далеко от того места, где они используются для экспорта значения из модуля. Это может уменьшить ясность. Конечно, вы можете объявить переменную после кода программы, но она по-прежнему имеет ту же область видимости (и var
водрузили). Кроме того, общая лучшая практика заключается в том, чтобы объявить все ваши переменные впереди, и не делать этого - это компромисс для рассмотрения.
- Код программы может беспорядочно перемещаться с вашими переменными, преднамеренно или случайно, что усложняет ситуацию и нежелательно, если вам это не нужно (иногда вы это делаете).
Второй пример устраняет эти проблемы, имея частную область для этой области файла. Вы все равно можете использовать переменные, охваченные всем файлом, но в тех случаях, когда это вам не нужно, вы можете иметь переменные, которые легче читать и понимать.
Часто мы программируем для людей, а не для машин. Это пример оптимизации для первого.
Update:
В современных версиях JavaScript const и let, вероятно, являются лучшими решениями проблем, которые этот шаблон пытается решить. С их помощью вы можете определить переменные таким образом, чтобы они выдавали ошибки, если вы делаете те же ошибки, с которыми IIFE пытается защитить вас.
//
// ... lots of program code here ...
//
const foo = 'la' + 'la'; // some computed value
module.exports = {
foo : foo,
};
В приведенном выше примере, если программный код использует foo
, он сработает с ReferenceError
, из-за Temporal Dead Zone, в отличие от приема undefined
в качестве var
. Это здорово, потому что теперь вы должны явно переместить объявление foo
в более раннее место в коде, если его использование было намеренным или иным образом исправить код.