From 841aae260382e2bf5ebb44d765d8c7301d27caab Mon Sep 17 00:00:00 2001 From: Alexey Istomin Date: Sat, 20 Mar 2021 18:37:44 +0300 Subject: Restore "ё" letter in Russian translation (#239) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(ru): restore ё letter * docs(ru): resolve conflicts * refactor(idea): remove ide folder --- files/ru/web/javascript/closures/index.html | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'files/ru/web/javascript/closures/index.html') diff --git a/files/ru/web/javascript/closures/index.html b/files/ru/web/javascript/closures/index.html index 0aaebde058..dde1d17511 100644 --- a/files/ru/web/javascript/closures/index.html +++ b/files/ru/web/javascript/closures/index.html @@ -8,7 +8,7 @@ translation_of: Web/JavaScript/Closures ---

{{jsSidebar("Intermediate")}}

-

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

+

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

Лексическая область видимости

@@ -51,7 +51,7 @@ myFunc();

На первый взгляд, кажется неочевидным, что этот код правильный, но он работает. В некоторых языках программирования локальные переменные-функции существуют только во время выполнения этой функции. После завершения выполнения makeFunc() можно ожидать, что переменная name больше не будет доступна. Однако, поскольку код продолжает нормально работать, очевидно, что это не так в случае JavaScript.

-

Причина в том, что функции в JavaScript формируют так называемые замыкания. Замыкание — это комбинация функции и лексического окружения, в котором эта функция была объявлена. Это окружение состоит из произвольного количества локальных переменных, которые были в области действия функции во время создания замыкания. В рассмотренном примере myFunc — это ссылка на экземпляр функции displayName, созданной в результате выполнения makeFunc. Экземпляр функции displayName в свою очередь сохраняет ссылку на своё лексическое окружение, в котором есть переменная name.  По этой причине, когда происходит вызов функции myFunc, переменная name остаётся доступной для использования и сохраненный в ней текст "Mozilla" передаётся в alert.

+

Причина в том, что функции в JavaScript формируют так называемые замыкания. Замыкание — это комбинация функции и лексического окружения, в котором эта функция была объявлена. Это окружение состоит из произвольного количества локальных переменных, которые были в области действия функции во время создания замыкания. В рассмотренном примере myFunc — это ссылка на экземпляр функции displayName, созданной в результате выполнения makeFunc. Экземпляр функции displayName в свою очередь сохраняет ссылку на своё лексическое окружение, в котором есть переменная name.  По этой причине, когда происходит вызов функции myFunc, переменная name остаётся доступной для использования и сохранённый в ней текст "Mozilla" передаётся в alert.

А вот немного более интересный пример — функция makeAdder:

@@ -70,7 +70,7 @@ console.log(add10(2)); // 12

Здесь мы определили функцию makeAdder(x), которая получает единственный аргумент x и возвращает новую функцию. Эта функция получает единственный аргумент y и возвращает сумму x и y.

-

По существу makeAdder — это фабрика функций: она создает функции, которые могут прибавлять определённое значение к своему аргументу. В примере выше мы используем нашу фабричную функцию для создания двух новых функций — одна прибавляет 5 к своему аргументу, вторая прибавляет 10.

+

По существу makeAdder — это фабрика функций: она создаёт функции, которые могут прибавлять определённое значение к своему аргументу. В примере выше мы используем нашу фабричную функцию для создания двух новых функций — одна прибавляет 5 к своему аргументу, вторая прибавляет 10.

add5 и add10 — это примеры замыканий. Эти функции делят одно определение тела функции, но при этом они сохраняют различные окружения. В окружении функции add5 x — это 5, в то время как в окружении add10 x — это 10.

@@ -80,7 +80,7 @@ console.log(add10(2)); // 12

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

-

Такие ситуации повсеместно встречаются в web-разработке. Большое количество front-end кода, который мы пишем на JavaScript, основано на обработке событий. Мы описываем какое-то поведение, а потом связываем его с событием, которое создается пользователем (например, клик мышкой или нажатие клавиши). При этом наш код обычно привязывается к событию в виде обратного/ответного вызова (callback): callback функция - функция выполняемая в ответ на возникновение события.

+

Такие ситуации повсеместно встречаются в web-разработке. Большое количество front-end кода, который мы пишем на JavaScript, основано на обработке событий. Мы описываем какое-то поведение, а потом связываем его с событием, которое создаётся пользователем (например, клик мышкой или нажатие клавиши). При этом наш код обычно привязывается к событию в виде обратного/ответного вызова (callback): callback функция - функция выполняемая в ответ на возникновение события.

Давайте рассмотрим практический пример: допустим, мы хотим добавить на страницу несколько кнопок, которые будут менять размер текста. Как вариант, мы можем указать свойство font-size на элементе body в пикселах, а затем устанавливать размер прочих элементов страницы (таких, как заголовки) с использованием относительных единиц em:

@@ -131,7 +131,7 @@ document.getElementById('size-16').onclick = size16;

Языки вроде Java позволяют нам объявлять частные (private) методы . Это значит, что они могут быть вызваны только методами того же класса, в котором объявлены.

-

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

+

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

Код ниже иллюстрирует, как можно использовать замыкания для определения публичных функций, которые имеют доступ к закрытым от пользователя (private) функциям и переменным. Такая манера программирования называется модульное программирование

@@ -161,13 +161,13 @@ Counter.decrement(); alert(Counter.value()); /* Alerts 1 */ -

Тут много чего поменялось. В предыдущем примере каждое замыкание имело свой собственный контекст исполнения (окружение). Здесь мы создаем единое окружение для трех функций: Counter.increment, Counter.decrement, и Counter.value.

+

Тут много чего поменялось. В предыдущем примере каждое замыкание имело свой собственный контекст исполнения (окружение). Здесь мы создаём единое окружение для трёх функций: Counter.increment, Counter.decrement, и Counter.value.

-

Единое окружение создается в теле анонимной функции, которая исполняется в момент описания. Это окружение содержит два приватных элемента: переменную privateCounter и функцию changeBy(val). Ни один из этих элементов не доступен напрямую, за пределами этой самой анонимной функции. Вместо этого они могут и должны использоваться тремя публичными функциями, которые возвращаются анонимным блоком кода (anonymous wrapper), выполняемым в той же анонимной функции.

+

Единое окружение создаётся в теле анонимной функции, которая исполняется в момент описания. Это окружение содержит два приватных элемента: переменную privateCounter и функцию changeBy(val). Ни один из этих элементов не доступен напрямую, за пределами этой самой анонимной функции. Вместо этого они могут и должны использоваться тремя публичными функциями, которые возвращаются анонимным блоком кода (anonymous wrapper), выполняемым в той же анонимной функции.

Эти три публичные функции являются замыканиями, использующими общий контекст исполнения (окружение). Благодаря механизму lexical scoping в Javascript, все они имеют доступ к переменной privateCounter и функции changeBy.

-

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

+

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

var makeCounter = function() {
   var privateCounter = 0;
@@ -198,7 +198,7 @@ alert(Counter1.value()); /* Alerts 1 */
 alert(Counter2.value()); /* Alerts 0 */
 
-

Заметьте, что счетчики работают независимо друг от друга. Это происходит потому, что у каждого из них в момент создания функцией makeCounter() также создавался свой отдельный контекст исполнения (окружение). То есть приватная переменная privateCounter в каждом из счетчиков это действительно отдельная, самостоятельная переменная.

+

Заметьте, что счётчики работают независимо друг от друга. Это происходит потому, что у каждого из них в момент создания функцией makeCounter() также создавался свой отдельный контекст исполнения (окружение). То есть приватная переменная privateCounter в каждом из счётчиков это действительно отдельная, самостоятельная переменная.

Используя замыкания подобным образом, вы получаете ряд преимуществ, обычно ассоциируемых с объектно-ориентированным программированием, таких как изоляция и инкапсуляция.

@@ -236,11 +236,11 @@ setupHelp();

{{JSFiddleEmbed("https://jsfiddle.net/v7gjv/13026/", "", 200)}}

-

Массив helpText описывает три подсказки для трех полей ввода. Цикл пробегает эти описания по очереди и для каждого из полей ввода определяет, что при возникновении события onfocus для этого элемента должна вызываться функция, показывающая соответствующую подсказку.

+

Массив helpText описывает три подсказки для трёх полей ввода. Цикл пробегает эти описания по очереди и для каждого из полей ввода определяет, что при возникновении события onfocus для этого элемента должна вызываться функция, показывающая соответствующую подсказку.

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

-

Проблема в том, что функции, присвоенные как обработчики события onfocus, являются замыканиями. Они состоят из описания функции и контекста исполнения (окружения), унаследованного от  функции setupHelp. Было создано три замыкания, но все они были созданы с одним и тем же контекстом исполнения. К моменту возникновения события onfocus цикл уже давно отработал, а значит, переменная item (одна и та же для всех трех замыканий) указывает на последний элемент массива, который как раз в поле возраста.

+

Проблема в том, что функции, присвоенные как обработчики события onfocus, являются замыканиями. Они состоят из описания функции и контекста исполнения (окружения), унаследованного от  функции setupHelp. Было создано три замыкания, но все они были созданы с одним и тем же контекстом исполнения. К моменту возникновения события onfocus цикл уже давно отработал, а значит, переменная item (одна и та же для всех трёх замыканий) указывает на последний элемент массива, который как раз в поле возраста.

В качестве решения в этом случае можно предложить использование функции, фабричной функции (function factory), как уже было описано выше в примерах:

@@ -272,7 +272,7 @@ setupHelp();

{{JSFiddleEmbed("https://jsfiddle.net/v7gjv/13024/", "", 200)}}

-

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

+

Вот это работает как следует. Вместо того, чтобы делить на всех одно окружение, функция makeHelpCallback создаёт каждому из замыканий своё собственное, в котором переменная item указывает на правильный элемент массива helpText.

Соображения по производительности

@@ -295,7 +295,7 @@ setupHelp(); } -

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

+

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

function MyObject(name, message) {
   this.name = name.toString();
-- 
cgit v1.2.3-54-g00ecf