Проблема с глобальной областью действия Javascript
Любой, кто имеет некоторый опыт программирования, знает, что глобальные переменные - это плохо. Javascript - не исключение. На самом деле управление областями переменных в Javascript еще хуже. Это особенно верно для больших корпоративных приложений, где приложение включает в себя большое количество скриптов, где очень вероятно столкновение областей видимости. Другие языки, такие как Java и C #, предоставляют функцию пространства имен, которая устраняет проблемы с загромождением глобальной области видимости и гарантирует, что области действия переменных ограничены областями, для которых они предназначены. К сожалению, в Javascript такой возможности нет. К счастью, существует ряд методов и шаблонов, которым можно следовать, чтобы предотвратить коллизию областей видимости и обеспечить масштабируемый код Javascript.

Создание простой переменной Javascript:
В приведенном ниже примере простая переменная Javascript «executeTask» определяется с помощью ключевого слова «var». Значение, присвоенное переменной, - это функция, которая записывается в консоль. Затем функция вызывается с использованием круглых скобок, и все работает как задумано.

var executeTask = function() {
  console.log("Executing a task");
}
executeTask();

Хотя приведенный выше код работает, проблема заключается в том, что переменная «executeTask» объявлена ​​в глобальной области видимости. Это так, потому что переменная не заключена ни в какие замыкания или не заключена в какие-либо функции. Следует помнить, что в Javascript области действия переменных применяются только внутри функций, а не в каких-либо других фигурных скобках, таких как операторы if или циклы. Это означает, что если другой сценарий объявляет переменную в глобальной области видимости под названием «executeTask», он столкнется с переменной, объявленной выше. Одно из двух объявлений в конечном итоге переопределит другое в зависимости от порядка загрузки скриптов.

Уменьшение беспорядка в глобальном масштабе
Рассмотрим ситуацию, когда нужно объявить несколько функций, связанных с «задачами». Можно было бы объединить все эти функции в один «модуль», а не объявлять их непосредственно в глобальной области видимости. Поскольку Javascript изначально не поддерживает понятие «модуль» в области имен, для имитации понятия модуля используются собственные функции Javascript.

В приведенном ниже примере объявляется «модуль» с именем «taskManager», в который входят две функции: executeTask и getTaskStatus. Поскольку эти две вложенные функции объявлены с использованием ключевого слова var в модуле taskManager, они не будут доступны из глобальной области видимости. Доступ к ним должен осуществляться с помощью оператора «.» В модуле «TaskManager». Чтобы этот шаблон работал, функция «taskManager» должна «раскрывать» все свои вложенные функции, выставляя их в возвращаемом ею объекте.

var taskManager = function() {
  
  var executeTask = function() {
    console.log("Executing a task");
  }
  
  var getTaskStatus = function() {
    console.log("Getting task status");
  }
  
  return {
    executeTask: executeTask,
    taskStatus: getTaskStatus
  }
}
taskManager().executeTask();

В приведенном выше примере обе локальные функции «executeTask» и «getTaskStatus» добавляются к возвращаемому объекту. Обратите внимание, что имя выставленного свойства не обязательно должно совпадать с именем функции. В приведенном выше примере «getTaskStatus» был представлен под именем «taskStatus». Обычно имена почти всегда совпадают, но не обязательно.

Немедленно вызываемые функции
В предыдущем примере объявленные функции были разделены на модули и инкапсулированы в модуль «taskManager». К ним можно легко получить доступ, вызвав сначала функцию «taskManager», которая возвращает и объект, раскрывая обе вложенные функции. Однако при таком подходе всегда нужно вызывать функцию «taskManager». Вместо того, чтобы делать это каждый раз, когда должна быть вызвана функция задачи, Javascript поддерживает немедленный вызов функции после объявления и сохранение возвращаемого объекта в переменной «taskManager». Таким образом, функция «taskManager» больше не является функцией, это будет литерал объекта, не требующий вызова.

var taskManager = function() {
  
  var executeTask = function() {
    console.log("Executing a task");
    alert("Executing a task");
  }
  
  var getTaskStatus = function() {
    console.log("Getting task status");
  }
  
  return {
    executeTask: executeTask,
    taskStatus: getTaskStatus
  }
}();
taskManager.executeTask();

Выражение немедленно вызываемой функции (IIFE)
Хотя все подходы работают, они по-прежнему включают объявление глобальной переменной. В предыдущем подходе глобальная переменная taskManager была объявлена ​​в глобальной области видимости. Это может быть проблемой, если в документ HTML добавлен другой Javascript и объявляется другая переменная с тем же именем. Чтобы полностью исключить эти переменные, Javascript позволяет обернуть весь модуль областью действия функции, которая вызывается немедленно. Эти обертки функций называются выражениями мгновенно вызываемых функций (IIFE, произносится как «iffies»). Это предотвратит добавление каких-либо переменных в глобальную область видимости. Можно подумать, что добавление пары скобок вызовет функцию-оболочку. Однако, поскольку он не назначен переменной, Javascript не позволяет этого. Чтобы решить эту проблему, функцию упаковки необходимо заключить в круглые скобки.

(function() {
  var taskManager = function() {
    
    var executeTask = function() {
      console.log("Executing a task");
      alert("Executing a task");
    }
    
    var getTaskStatus = function() {
      console.log("Getting task status");
    }
    
    return {
      executeTask: executeTask,
      taskStatus: getTaskStatus
    }
  }();
  
  taskManager.executeTask();