0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Если вы построите химический завод, неплохо бы изолировать его от окружающего мира, чтобы не произошла утечка химикатов. Можно сказать, что в этом здании свое<strong>окружение</strong>- микроклимат, изолированный от внешней окружающей среды.</p>
1
<p>Если вы построите химический завод, неплохо бы изолировать его от окружающего мира, чтобы не произошла утечка химикатов. Можно сказать, что в этом здании свое<strong>окружение</strong>- микроклимат, изолированный от внешней окружающей среды.</p>
2
<p>В программировании такая изоляция называется<strong>областью видимости</strong>. В этом уроке мы поговорим об окружении. Вы узнаете, на какие зоны делятся программы и как это влияет на работу кода.</p>
2
<p>В программировании такая изоляция называется<strong>областью видимости</strong>. В этом уроке мы поговорим об окружении. Вы узнаете, на какие зоны делятся программы и как это влияет на работу кода.</p>
3
<h2>Области видимости</h2>
3
<h2>Области видимости</h2>
4
<p>С точки зрения окружения, программы делятся на две области видимости:</p>
4
<p>С точки зрения окружения, программы делятся на две области видимости:</p>
5
<ul><li>Глобальную (внешнюю)</li>
5
<ul><li>Глобальную (внешнюю)</li>
6
<li>Локальную (внутреннюю)</li>
6
<li>Локальную (внутреннюю)</li>
7
</ul><p>В глобальной области видимости находится все, что мы создаем снаружи функций, инструкций if, циклов и других блоков кода:</p>
7
</ul><p>В глобальной области видимости находится все, что мы создаем снаружи функций, инструкций if, циклов и других блоков кода:</p>
8
<p>В этом примере константа age, функция multiplier и переменная result имеют глобальную область видимости.</p>
8
<p>В этом примере константа age, функция multiplier и переменная result имеют глобальную область видимости.</p>
9
<p>Поговорим подробнее о локальной зоне видимости из этого примера. Внутри функции multiplier есть константа x. Она находится внутри блока кода, она видна только внутри этой функции.</p>
9
<p>Поговорим подробнее о локальной зоне видимости из этого примера. Внутри функции multiplier есть константа x. Она находится внутри блока кода, она видна только внутри этой функции.</p>
10
<p>В функции multiplier есть еще один компонент из локальной области видимости - аргумент num. Он не задан так же четко, как константы или переменные, но ведет себя почти как локальная переменная.</p>
10
<p>В функции multiplier есть еще один компонент из локальной области видимости - аргумент num. Он не задан так же четко, как константы или переменные, но ведет себя почти как локальная переменная.</p>
11
<p>У нас нет доступа к x снаружи, как будто ее там не существует:</p>
11
<p>У нас нет доступа к x снаружи, как будто ее там не существует:</p>
12
<p>В этом примере console.log вызывается в глобальном окружении, но при этом x не задан глобально. Поэтому мы получаем сообщение Reference Error.</p>
12
<p>В этом примере console.log вызывается в глобальном окружении, но при этом x не задан глобально. Поэтому мы получаем сообщение Reference Error.</p>
13
<p>Попробуем задать x глобально:</p>
13
<p>Попробуем задать x глобально:</p>
14
<p>Теперь существует глобальный x. Мы вывели его значение на экран, но локальный x внутри функции multiplier по-прежнему виден только внутри этой функции.</p>
14
<p>Теперь существует глобальный x. Мы вывели его значение на экран, но локальный x внутри функции multiplier по-прежнему виден только внутри этой функции.</p>
15
<p>Эти два x не имеют ничего общего друг с другом, они находятся в разных областях видимости. Они не схлопываются в одно целое, несмотря на одинаковое имя.</p>
15
<p>Эти два x не имеют ничего общего друг с другом, они находятся в разных областях видимости. Они не схлопываются в одно целое, несмотря на одинаковое имя.</p>
16
<p>Любой блок кода между фигурными скобками имеет локальную область видимости. Вот пример с блоком if:</p>
16
<p>Любой блок кода между фигурными скобками имеет локальную область видимости. Вот пример с блоком if:</p>
17
<p>То же работает для циклов while и for.</p>
17
<p>То же работает для циклов while и for.</p>
18
<p>Теперь мы знаем, что локальное недоступно снаружи, а глобальное - доступно везде. Даже внутри чего-то? Да, и это видно в примере ниже:</p>
18
<p>Теперь мы знаем, что локальное недоступно снаружи, а глобальное - доступно везде. Даже внутри чего-то? Да, и это видно в примере ниже:</p>
19
<p>Эта глобальная переменная a изменилась внутри функции changer. Функция выполняет что-то, только когда ее вызывают, а не когда ее определяют. Поэтому вначале a это 0, но после вызова changer переменная a становится 1.</p>
19
<p>Эта глобальная переменная a изменилась внутри функции changer. Функция выполняет что-то, только когда ее вызывают, а не когда ее определяют. Поэтому вначале a это 0, но после вызова changer переменная a становится 1.</p>
20
<p>Может показаться, что было бы удобно все поместить в глобальную область видимости и забыть о сложностях. На самом деле, это ужасная практика. Глобальные переменные делают код невероятно хрупким. В таком случае может сломаться все что угодно. Поэтому избегайте глобальной области видимости - храните вещи там, где им место.</p>
20
<p>Может показаться, что было бы удобно все поместить в глобальную область видимости и забыть о сложностях. На самом деле, это ужасная практика. Глобальные переменные делают код невероятно хрупким. В таком случае может сломаться все что угодно. Поэтому избегайте глобальной области видимости - храните вещи там, где им место.</p>
21
<h2>Лексическая область видимости</h2>
21
<h2>Лексическая область видимости</h2>
22
<p>Кроме глобальной и локальной, существует еще и<strong>лексическая область видимости</strong>. Это конкретный механизм, одно из правил для области видимости, которое применяется в JavaScript и большинстве других языков.</p>
22
<p>Кроме глобальной и локальной, существует еще и<strong>лексическая область видимости</strong>. Это конкретный механизм, одно из правил для области видимости, которое применяется в JavaScript и большинстве других языков.</p>
23
<p>Под лексической областью видимости можно понимать просто механизм поиска значений: смотрим в текущей области, если нет - идем на уровень выше, и так далее. Слово "лексический" означает, что видимость задается исключительно текстом программы.</p>
23
<p>Под лексической областью видимости можно понимать просто механизм поиска значений: смотрим в текущей области, если нет - идем на уровень выше, и так далее. Слово "лексический" означает, что видимость задается исключительно текстом программы.</p>
24
<p>Другими словами, мы можем, посмотреть на текст программы и узнать область видимости в любой точке. В других языках может быть не лексический механизм, а<a>динамический</a>.</p>
24
<p>Другими словами, мы можем, посмотреть на текст программы и узнать область видимости в любой точке. В других языках может быть не лексический механизм, а<a>динамический</a>.</p>
25
<p>Разберемся, как лексическая область работает на практике. Взгляните на эту программу:</p>
25
<p>Разберемся, как лексическая область работает на практике. Взгляните на эту программу:</p>
26
<p>Функция multiplier возвращает произведение a и b. Значение a задано внутри, а b - нет.</p>
26
<p>Функция multiplier возвращает произведение a и b. Значение a задано внутри, а b - нет.</p>
27
<p>Пытаясь решить умножение a * b, JavaScript ищет значения a и b. Он начинает искать локально и выходит наружу по одной области видимости за шаг. Так происходит до тех пор, пока JavaScript:</p>
27
<p>Пытаясь решить умножение a * b, JavaScript ищет значения a и b. Он начинает искать локально и выходит наружу по одной области видимости за шаг. Так происходит до тех пор, пока JavaScript:</p>
28
<ul><li>Не найдет то, что нужно</li>
28
<ul><li>Не найдет то, что нужно</li>
29
<li>Не увидит, что это невозможно найти</li>
29
<li>Не увидит, что это невозможно найти</li>
30
</ul><p>В этом примере JavaScript начинает с поиска a внутри локальной области видимости - внутри функции multiplier. Он находит значение сразу и переходит к b. Невозможно найти значение b в локальной области видимости, поэтому он переходит к внешней области. Тут он находит b - это 10. Таким образом a * b превращается в 5 * 10, а затем - в 50.</p>
30
</ul><p>В этом примере JavaScript начинает с поиска a внутри локальной области видимости - внутри функции multiplier. Он находит значение сразу и переходит к b. Невозможно найти значение b в локальной области видимости, поэтому он переходит к внешней области. Тут он находит b - это 10. Таким образом a * b превращается в 5 * 10, а затем - в 50.</p>
31
<p>Весь этот кусок кода может быть внутри другой функции, и еще внутри другой функции. Если бы b не нашлась здесь, JavaScript продолжил бы искать b за пределами функции, слой за слоем.</p>
31
<p>Весь этот кусок кода может быть внутри другой функции, и еще внутри другой функции. Если бы b не нашлась здесь, JavaScript продолжил бы искать b за пределами функции, слой за слоем.</p>
32
<p>Заметьте, что a = 7 не затрагивает вычисления. Значение a нашлось внутри, поэтому внешняя a не сыграла роли.</p>
32
<p>Заметьте, что a = 7 не затрагивает вычисления. Значение a нашлось внутри, поэтому внешняя a не сыграла роли.</p>
33
<p>Этот механизм называется<strong>лексической областью видимости</strong>. Область видимости любого компонента определяется его расположением внутри кода. И вложенные блоки имеют доступ к их внешним областям видимости.</p>
33
<p>Этот механизм называется<strong>лексической областью видимости</strong>. Область видимости любого компонента определяется его расположением внутри кода. И вложенные блоки имеют доступ к их внешним областям видимости.</p>
34
<h2>Замыкание</h2>
34
<h2>Замыкание</h2>
35
<p>Большинство языков программирования имеют что-то вроде области видимости или окружения, и этот механизм позволяет существовать замыканиям.</p>
35
<p>Большинство языков программирования имеют что-то вроде области видимости или окружения, и этот механизм позволяет существовать замыканиям.</p>
36
<p><strong>Замыкание</strong>- это сочетание функции и окружения, где она была заявлена. Другими словами, это всего лишь новое название функции, которая запоминает внешние штуки, используемые внутри.</p>
36
<p><strong>Замыкание</strong>- это сочетание функции и окружения, где она была заявлена. Другими словами, это всего лишь новое название функции, которая запоминает внешние штуки, используемые внутри.</p>
37
<p>Давайте вспомним, как функции создаются и используются:</p>
37
<p>Давайте вспомним, как функции создаются и используются:</p>
38
<p>Функция f довольно бесполезная, она всегда возвращает 0. Весь этот набор состоит из двух частей:</p>
38
<p>Функция f довольно бесполезная, она всегда возвращает 0. Весь этот набор состоит из двух частей:</p>
39
<ul><li>Константы</li>
39
<ul><li>Константы</li>
40
<li>Самой функции</li>
40
<li>Самой функции</li>
41
</ul><p>Важно помнить, что эти два компонента раздельны. Первый - константа с именем f. Ее значение могло бы быть числом или строкой, но здесь это функция.</p>
41
</ul><p>Важно помнить, что эти два компонента раздельны. Первый - константа с именем f. Ее значение могло бы быть числом или строкой, но здесь это функция.</p>
42
<p>Когда мы вызываем эту функцию, это выглядит вот так:</p>
42
<p>Когда мы вызываем эту функцию, это выглядит вот так:</p>
43
<p>Вернемся к замыканиям и рассмотрим следующий код:</p>
43
<p>Вернемся к замыканиям и рассмотрим следующий код:</p>
44
<p>Функция createPrint создает константу name и затем функцию с именем printName. Созданные функция и константа локальны - они доступны только внутри createPrint.</p>
44
<p>Функция createPrint создает константу name и затем функцию с именем printName. Созданные функция и константа локальны - они доступны только внутри createPrint.</p>
45
<p>У самой printName нет локальных компонентов. Но у нее есть доступ к своей области видимости - то есть к внешней области, где задана константа name.</p>
45
<p>У самой printName нет локальных компонентов. Но у нее есть доступ к своей области видимости - то есть к внешней области, где задана константа name.</p>
46
<p>Затем функция createPrint возвращает функцию printName. Помните, что определения функций - это описания запущенных функций, просто фрагменты информации, как числа или строки. Поэтому мы можем вернуть определение функции, как мы возвращаем число.</p>
46
<p>Затем функция createPrint возвращает функцию printName. Помните, что определения функций - это описания запущенных функций, просто фрагменты информации, как числа или строки. Поэтому мы можем вернуть определение функции, как мы возвращаем число.</p>
47
<p>Во внешней области видимости мы создаем константу myPrint и задаем ей значение, которое возвращает вызов функции createPrint(). Этот вызов возвращает функцию, так что теперь myPrint - это функция. Вызовите ее, и на экран выведется King.</p>
47
<p>Во внешней области видимости мы создаем константу myPrint и задаем ей значение, которое возвращает вызов функции createPrint(). Этот вызов возвращает функцию, так что теперь myPrint - это функция. Вызовите ее, и на экран выведется King.</p>
48
<p>Тут есть одна странная штука: эта константа name была создана внутри функции createPrint. Функция была вызвана и исполнена. Как мы знаем, когда функция заканчивает работу, она больше не существует.</p>
48
<p>Тут есть одна странная штука: эта константа name была создана внутри функции createPrint. Функция была вызвана и исполнена. Как мы знаем, когда функция заканчивает работу, она больше не существует.</p>
49
<p>Этот магический ящик исчезает со всеми своими внутренностями, но он возвращает другую функцию, и уже она запоминает константу name. Поэтому когда мы вызывали myPrint(), она вывела King - запомненное значение. При этом больше не существует та область видимости, где мы задали это значение.</p>
49
<p>Этот магический ящик исчезает со всеми своими внутренностями, но он возвращает другую функцию, и уже она запоминает константу name. Поэтому когда мы вызывали myPrint(), она вывела King - запомненное значение. При этом больше не существует та область видимости, где мы задали это значение.</p>
50
<p>Функция, которую мы вернули из createPrint - это и есть замыкание. Другими словами, это сочетание функции и окружения, где она была задана. Функция замкнула в себе некоторую информацию из области видимости.</p>
50
<p>Функция, которую мы вернули из createPrint - это и есть замыкание. Другими словами, это сочетание функции и окружения, где она была задана. Функция замкнула в себе некоторую информацию из области видимости.</p>
51
<p>Если использовать их разумно, замыкания могут сделать код приятней, чище и проще для чтения. Даже сама идея возврата функций тем же способом, которым можно возвращать числа и строки, дает больше возможностей и гибкости.</p>
51
<p>Если использовать их разумно, замыкания могут сделать код приятней, чище и проще для чтения. Даже сама идея возврата функций тем же способом, которым можно возвращать числа и строки, дает больше возможностей и гибкости.</p>
52
<p>Вы заметите, как часто эти идеи используются в программировании. Мы рассмотрим их потенциал в следующих курсах.</p>
52
<p>Вы заметите, как часто эти идеи используются в программировании. Мы рассмотрим их потенциал в следующих курсах.</p>