HTML Diff
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>