Как работают замыкания в JavaScript - Stack Overflow на русском. Изучаем замыкания в JavaScript Как работают замыкания javascript

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

Введение

В сети довольно много статей, в которых пытаются объяснить области видимости и замыкания, но в общем, я бы сказал, что большинство из них не совсем понятны. Кроме того, в некоторых статьях предполагается, что вы программировали до этого на 15 других языках, хотя как я считаю - большинство людей пишущих на JavaScript имеют лишь опыт в HTML и CSS, а не в C или Java.

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

Область видимости

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

Глобальная область видимости

Когда что-то является глобальным, это значит, что оно доступно из любого места в вашем коде. Рассмотрим пример:

var monkey = "Gorilla"; function greetVisitor () { return alert("Hello dear blog reader!"); }

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

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

В отличие от глобальной области видимости, локальная область видимости - это когда что-то определено и доступно только в некоторой части кода, как например функция. Рассмотрим пример:

function talkDirty () { var saying = "Oh, you little VB lover, you"; return alert(saying); } alert(saying); // Throws an error

В данном примере переменная saying доступна только внутри функции talkDirty, за пределами которой она не определена. Замечание: если бы вы определили saying без ключевого слова var, то она автоматически стала бы глобальной.

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

function saveName (firstName) { function capitalizeName () { return firstName.toUpperCase(); } var capitalized = capitalizeName(); return capitalized; } alert(saveName("Robert")); // Returns "ROBERT"

Как вы только что увидели, внутренней функции capitalizeName не нужно передавать никаких параметров, т.к. она имеет полный доступ к параметру firstName во внешней функции saveName. Для большей ясности, рассмотрим еще один пример:

function siblings () { var siblings = ["John", "Liza", "Peter"]; function siblingCount () { var siblingsLength = siblings.length; return siblingsLength; } function joinSiblingNames () { return "I have " + siblingCount() + " siblings:nn" + siblings.join("n"); } return joinSiblingNames(); } alert(siblings()); // Outputs "I have 3 siblings: John Liza Peter"

Как вы видите, обе внутренние функции имеют доступ к массиву siblings, и каждая внутренняя функция имеет доступ к другой внутренней функции того же уровня (в данном случае joinSiblingNames имеет доступ к siblingCount). Однако, переменная siblingsLength внутри siblingCount доступна лишь внутри этой функции, т.е. в этой области видимости.

Замыкание

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

function add (x) { return function (y) { return x + y; }; } var add5 = add(5); var no8 = add5(3); alert(no8); // Returns 8

Вот это да! Что здесь происходит? Давайте разбираться:

1. Когда мы вызываем функцию add, она возвращает функцию.

2. Эта функция закрывает контекст и запоминает, каким был параметр x в это время (т.е. в данном случае значением 5)

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

4. Переменная add5 ссылается на функцию, которая всегда будет добавлять значение 5 к любому переданному ей аргументу.

5. Это означает, что когда мы вызываем add5 со значением 3, она сложит числа 5 и 3, и вернет 8.

На самом деле, в мире JavaScript, функция add5 выглядит следующим образом:

function add5 (y) { return 5 + y; }

Пресловутая проблема циклов
Сколько раз вы создавали циклы, в которых хотели присвоить значение i каким-либо образом, например элементу, и понимали, что возвращается лишь последнее значение i?

Неправильное обращение

Давайте посмотрим на этот некорректный код, который создает 5 элементов , добавляет значение i как текст к каждому элементу и onclick, который как ожидается будет выдавать alert со значением i для данной ссылки, т.е. то же самое значение, что и в тексте элемента. Затем элементы добавляются к document body:

Железо ПК