Области видимости и замыкания важны в JavaScript. Но они сбивали меня с толку, когда я только начинал 😇😇. Вот объяснение областей действия и замыканий, чтобы помочь вам понять, что они из себя представляют.

Правильное понимание этих концепций поможет вам писать более качественный, эффективный и чистый код 🤩.

Итак, без лишних слов, приступим 😀

Что такое Сфера?

Текущий контекст выполнения. Контекст, в котором значения и выражения «видимы» или на которые можно ссылаться. Если переменная или другое выражение не находится «в текущей области видимости», то оно недоступно для использования.

Почему объем важен?

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

Типы области

В JavaScript существует три типа области действия: 1) глобальная область действия, 2) область действия функции и 3) область действия блока.

1. Глобальный масштаб

Любая переменная, не находящаяся внутри какой-либо функции или блока (пары фигурных скобок), находится внутри глобальной области видимости. После того как вы объявили глобальную переменную, вы можете использовать ее в любом месте вашего кода, даже в функциях. Например:

Хотя вы можете объявлять переменные в глобальной области видимости, делать этого не рекомендуется. Это связано с тем, что существует вероятность коллизии имен, когда две или более переменных имеют одинаковые имена. Если бы вы объявили свои переменные с помощью const или let, вы бы получили сообщение об ошибке всякий раз, когда происходит конфликт имен.

Если вы используете VS Code и установлен quick-lint-js, то вы увидите что-то вроде этого 👇🏼

Если вы объявляете свои переменные с помощью var, ваша вторая переменная перезаписывает первую после того, как она объявлена ​​​​таким образом 👇🏼

Таким образом, вы всегда должны объявлять локальные переменные, а не глобальные переменные.

2. Локальная область или область действия

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

В приведенном выше примере👆🏼 переменная приветствие находится в области приветствия.

3. Область блока

В ES6 появились переменные let и const, в отличие от переменных var, область действия которых может быть ограничена ближайшей парой фигурных скобок. Это означает, что к ним нельзя получить доступ из-за пределов этой пары фигурных скобок. Например:

Мы видим, что переменные var могут использоваться вне блока, то есть переменные var не относятся к блоку.

Вложенная область

Как и функции в JavaScript, область действия может быть вложена в другую область действия. Например:

Закрытия

Замыкание — это комбинация функции, связанной вместе (вложенной) со ссылками на ее окружающее состояние (лексическое окружение). Другими словами, замыкание дает вам доступ к области действия внешней функции из внутренней функции. В JavaScript замыкания создаются каждый раз, когда создается функция, во время создания функции…..

Хм запутался прямо..🤩🤩 Я знаю….Поясню на примере, А теперь ответьте на этот вопрос.

Вы уже записали код в консоль и получили ответ, но как?

Во-первых, давайте удостоверимся, сколько функций в приведенном выше коде? Мы видим, что в приведенном выше коде ключевое слово function используется в двух местах, поэтому в приведенном выше коде есть две функции, а именно первая строка function foo(a,b) { и четвертая строка foo: function(c){ . И эти две функции имеют одно и то же имя.

Второй вопрос: какую функцию вызывает foo (c, a) в строке 5? Если вы не уверены, давайте рассмотрим более простой пример:

Зачем поздно открывать браузер (хром) и открывать инструменты разработчика (используйте Option + ⌘ + J (в macOS) или Shift + CTRL + J (в Windows/Linux). Теперь скопируйте и вставьте код и запустите, вы увидите что-то вроде этот.

Это связано с тем, что верхняя область видимости метода obj.fn() является глобальной, и доступ к методу fn внутри obj недоступен. Возвращаясь к нашему предыдущему примеру, по той же логике, когда мы вызываем foo(c, a), мы фактически вызываем функцию foo в первой строке. И когда мы вызываем res.foo(1), какой foo вызывается? Очевидно, вызывается функция foo в 4-й строке.

Поскольку две функции foo работают по-разному, мы можем изменить имя одной из них на bar, чтобы нам было легче понимать код.

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

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

Когда мы выполняем let res = foo(0);, мы на самом деле выполняем foo(0, undefiend). В этот момент в программе создается новая область, в текущей области, a=0, b=undefined. Итак, схема, которую я нарисовал, выглядит примерно так.

Затем будет выполнен console.log(b), поэтому в первый раз он выведет в консоли undefined. Затем выполняется res.bar(1), создавая новую область видимости, где c=1:

И затем foo(c, a) снова вызывается из вышеупомянутой функции, которая на самом деле является foo(1, 0), и область видимости выглядит так:

В новой области значение a равно 1, а значение b равно 0, поэтому консоль выведет 0.

Далее снова выполняется res.bar(1). Обратите внимание, что res.bar(2) и res.bar(1) являются параллельными отношениями, поэтому мы должны нарисовать диаграмму области следующим образом:

Итак, в этом коде консоль также выводит значение 0. То же самое касается процесса, который выполняет res.bar(3), а консоль по-прежнему выводит 0. Таким образом, конечный результат кода выше:

На самом деле поставленный выше вопрос можно изменить и другими способами. Например, его можно изменить на следующее:

Прежде чем мы решим этот вопрос, первое, что нам нужно сделать, это различить две разные функции foo, поэтому приведенный выше код можно изменить, чтобы он выглядел следующим образом:

Когда он выполняет foo(0), область действия остается такой же, как и раньше, а затем консоль выводит «undefined».

Затем выполните .bar(1), чтобы создать новую область. Этот параметр 1 на самом деле является значением c.

Затем метод .bar(1) снова вызывает foo(c, a), что на самом деле является foo(1, 0). Параметр 1 здесь фактически будет значением a в новой области, а 0 будет значением b в новой области.

Таким образом, консоль выводит значение b, равное 0. .bar(2) вызывается снова с 2 в качестве значения c в новой области видимости:

А затем .bar(2) вызывает foo(c, a), что на самом деле является foo(2, 1), где 2 — это значение a в новой области видимости, а 1 — значение b в новой области видимости.

Итак, консоль выводит значение b, равное 0.

А затем он выполнит .bar(3), процесс такой же, как и раньше, поэтому я не буду расширять описание, на этом шаге консоль выводит 2.

Как упоминалось выше, окончательный результат выполнения кода:

Что ж, после долгого пути мы наконец получили ответ.

Надеюсь, вам понравилось, пока вы читали это… 😀😀.