Что такое замыкание в javascript

Что такое замыкание в javascript

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Более новая информация по этой теме находится на странице https://learn.javascript.ru/closure.

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

Лексическое окружение

Все переменные внутри функции – это свойства специального внутреннего объекта LexicalEnvironment , который создаётся при её запуске.

Мы будем называть этот объект «лексическое окружение» или просто «объект переменных».

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

В отличие от window , объект LexicalEnvironment является внутренним, он скрыт от прямого доступа.

Пример

Посмотрим пример, чтобы лучше понимать, как это работает:

При вызове функции:

До выполнения первой строчки её кода, на стадии инициализации, интерпретатор создаёт пустой объект LexicalEnvironment и заполняет его.

В данном случае туда попадает аргумент name и единственная переменная phrase :

Во время выполнения происходит присвоение локальной переменной phrase , то есть, другими словами, присвоение свойству LexicalEnvironment.phrase нового значения:

В конце выполнения функции объект с переменными обычно выбрасывается и память очищается. В примерах выше так и происходит. Через некоторое время мы рассмотрим более сложные ситуации, при которых объект с переменными сохраняется и после завершения функции.

Если почитать спецификацию ECMA-262, то мы увидим, что речь идёт о двух объектах: VariableEnvironment и LexicalEnvironment .

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

Более формальное описание находится в спецификации ECMA-262, секции 10.2-10.5 и 13.

Доступ ко внешним переменным

Из функции мы можем обратиться не только к локальной переменной, но и к внешней:

Интерпретатор, при доступе к переменной, сначала пытается найти переменную в текущем LexicalEnvironment , а затем, если её нет – ищет во внешнем объекте переменных. В данном случае им является window .

Такой порядок поиска возможен благодаря тому, что ссылка на внешний объект переменных хранится в специальном внутреннем свойстве функции, которое называется [[Scope]] . Это свойство закрыто от прямого доступа, но знание о нём очень важно для понимания того, как работает JavaScript.

При создании функция получает скрытое свойство [[Scope]] , которое ссылается на лексическое окружение, в котором она была создана.

В примере выше таким окружением является window , так что создаётся свойство:

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

При запуске функции её объект переменных LexicalEnvironment получает ссылку на «внешнее лексическое окружение» со значением из [[Scope]] .

Если переменная не найдена в функции – она будет искаться снаружи.

Именно благодаря этой механике в примере выше alert(userName) выводит внешнюю переменную. На уровне кода это выглядит как поиск во внешней области видимости, вне функции.

  • Каждая функция при создании получает ссылку [[Scope]] на объект с переменными, в контексте которого была создана.
  • При запуске функции создаётся новый объект с переменными LexicalEnvironment . Он получает ссылку на внешний объект переменных из [[Scope]] .
  • При поиске переменных он осуществляется сначала в текущем объекте переменных, а потом – по этой ссылке.

Выглядит настолько просто, что непонятно – зачем вообще говорить об этом [[Scope]] , об объектах переменных. Сказали бы: «Функция читает переменные снаружи» – и всё. Но знание этих деталей позволит нам легко объяснить и понять более сложные ситуации, с которыми мы столкнёмся далее.

Всегда текущее значение

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

Например, в коде ниже функция sayHi берёт phrase из внешней области:

На момент первого запуска (*) , переменная phrase имела значение ‘Привет’ , а ко второму (**) изменила его на ‘Пока’ .

Это естественно, ведь для доступа к внешней переменной функция по ссылке [[Scope]] обращается во внешний объект переменных и берёт то значение, которое там есть на момент обращения.

Вложенные функции

Внутри функции можно объявлять не только локальные переменные, но и другие функции.

К примеру, вложенная функция может помочь лучше организовать код:

Здесь, для удобства, создана вспомогательная функция getFullName() .

Вложенные функции получают [[Scope]] так же, как и глобальные. В нашем случае:

Благодаря этому getFullName() получает снаружи firstName и lastName .

Заметим, что если переменная не найдена во внешнем объекте переменных, то она ищется в ещё более внешнем (через [[Scope]] внешней функции), то есть, такой пример тоже будет работать:

Возврат функции

Рассмотрим более «продвинутый» вариант, при котором внутри одной функции создаётся другая и возвращается в качестве результата.

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

Здесь мы будем создавать функцию-счётчик, которая считает свои вызовы и возвращает их текущее число.

В примере ниже makeCounter создаёт такую функцию:

Как видно, мы получили два независимых счётчика counter и counter2 , каждый из которых незаметным снаружи образом сохраняет текущее количество вызовов.

Где? Конечно, во внешней переменной currentCount , которая у каждого счётчика своя.

Если подробнее описать происходящее:

В строке (*) запускается makeCounter() . При этом создаётся LexicalEnvironment для переменных текущего вызова. В функции есть одна переменная var currentCount , которая станет свойством этого объекта. Она изначально инициализуется в undefined , затем, в процессе выполнения, получит значение 1 :

В процессе выполнения makeCounter() создаёт функцию в строке (**) . При создании эта функция получает внутреннее свойство [[Scope]] со ссылкой на текущий LexicalEnvironment .

Далее вызов makeCounter() завершается и функция (**) возвращается и сохраняется во внешней переменной counter (*) .

На этом создание «счётчика» завершено.

Итоговым значением, записанным в переменную counter , является функция:

Возвращённая из makeCounter() функция counter помнит (через [[Scope]] ) о том, в каком окружении была создана.

Это и используется для хранения текущего значения счётчика.

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

Читайте также:  Что помогает от фингала

Эта функция состоит из одной строки: return currentCount++ , ни переменных ни параметров в ней нет, поэтому её собственный объект переменных, для краткости назовём его LE – будет пуст.

Однако, у неё есть свойство [[Scope]] , которое указывает на внешнее окружение. Чтобы увеличить и вернуть currentCount , интерпретатор ищет в текущем объекте переменных LE , не находит, затем идёт во внешний объект, там находит, изменяет и возвращает новое значение:

Переменную во внешней области видимости можно не только читать, но и изменять.

В примере выше было создано несколько счётчиков. Все они взаимно независимы:

Они независимы, потому что при каждом запуске makeCounter создаётся свой объект переменных LexicalEnvironment , со своим свойством currentCount , на который новый счётчик получит ссылку [[Scope]] .

Свойства функции

Функция в JavaScript является объектом, поэтому можно присваивать свойства прямо к ней, вот так:

Свойства функции не стоит путать с переменными и параметрами. Они совершенно никак не связаны. Переменные доступны только внутри функции, они создаются в процессе её выполнения. Это – использование функции «как функции».

А свойство у функции – доступно отовсюду и всегда. Это – использование функции «как объекта».

Если хочется привязать значение к функции, то можно им воспользоваться вместо внешних переменных.

В качестве демонстрации, перепишем пример со счётчиком:

При запуске пример работает также.

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

Например, можно взять и поменять счётчик из внешнего кода:

Иногда свойства, привязанные к функции, называют «статическими переменными».

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

Итого: замыкания

Замыкание – это функция вместе со всеми внешними переменными, которые ей доступны.

Таково стандартное определение, которое есть в Wikipedia и большинстве серьёзных источников по программированию. То есть, замыкание – это функция + внешние переменные.

Тем не менее, в JavaScript есть небольшая терминологическая особенность.

Обычно, говоря «замыкание функции», подразумевают не саму эту функцию, а именно внешние переменные.

Иногда говорят «переменная берётся из замыкания». Это означает – из внешнего объекта переменных.

Иногда говорят «Вася молодец, понимает замыкания!». Что это такое – «понимать замыкания», какой смысл обычно вкладывают в эти слова?

«Понимать замыкания» в JavaScript означает понимать следующие вещи:

  1. Все переменные и параметры функций являются свойствами объекта переменных LexicalEnvironment . Каждый запуск функции создаёт новый такой объект. На верхнем уровне им является «глобальный объект», в браузере – window .
  2. При создании функция получает системное свойство [[Scope]] , которое ссылается на LexicalEnvironment , в котором она была создана.
  3. При вызове функции, куда бы её ни передали в коде – она будет искать переменные сначала у себя, а затем во внешних LexicalEnvironment с места своего «рождения».

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

Всем привет! В этой статье мы рассмотрим, что такое замыкание в javascript.

Это довольно простая тема, но она требует понимания. Для начала давайте рассмотрим, что происходит внутри функции.

Что здесь происходит и что такое LexicalEnvironment? Давайте разберемся.

Когда функция вызывается, у нее создается объект LexicalEnvironment, в который записываются все локальные переменные и функции, а также ссылка на внешнюю область видимости(об этом позже). В нашем случае у нас есть локальная переменная name, у которой сразу есть значение(то, которое мы передаем) и это "Николай". В одной из статей я уже писал, однако напомню, что интерпретатор все знает про все переменные заранее. Именно по этому у нас в самом начале функции уже есть переменная text, интерпретатор знает про нее, но так как мы еще не дошли по присваивания этой переменной какого-то значения, то она равна undefined. Теперь мы присваиваем переменной значение, и наш объект LexicalEnvironment меняется. Его свойство text становится равным тому, что мы записали("Здравствуйте, Николай" в нашем случае). После того, как функция отработала, объект LexicalEnvironment уничтожается. При последующих вызовах функции он будет создан снова и т.д.

Теперь перейдем к следующему примеру. Скажите, что будет выведено в этом случае?

var b = 2;
function x(a) <
alert(a + b);
>
x(1);

Подумали? Думаю, большинство ответило, что будет выведено число 3, и это правильный ответ, однако можете вы рассказать, как интерпретатор узнал о переменной b? Ведь ее нет в теле функции. Если нет, давайте разбираться.

На самом деле в javascript есть скрытое свойство, которое называется [[Scope]]. Когда функция объявляется, то она всегда объявляется где-то. Эта функция может быть в другой функции, может быть в глобальном объекте и т.д. В нашем случае функция объявлена в глобальном объекте window, поэтому свойство x.[[Scope]] = window.

Дальше будем рассматривать на примере кода с комментариями.

var b = 2;
function x(a) < // x.[[Scope]] = window
// LexicalEnvironment = -> window
alert(a + b);
>
x(1);

Эта стрелочка у объекта LexicalEnvironment — это ссылка на внешнюю область видимости, и эта ссылка устанавливается по свойству [[Scope]]. Таким образом в объекте LexicalEnvironment у нас будет ссылка на внешний объект window. Когда интерпретатор ищет переменную, то он сначала ищет ее в объекте LexicalEnvironment, затем, если он не нашел переменную, то он смотрим в ссылку, переходит во внешнюю область видимости и ищет ее там и так до конца. Если он нигде этой переменной не нашел, то будет ошибка. В нашем случае переменную a интерпретатор возьмет из объекта LexicalEnvironment, а переменную b из объекта window. Конечно, если у нас будет локальная переменная b с каким-то значением, то она запишется в объект LexicalEnvironment и впоследствии будет взята оттуда, а не из внешней области видимости.

ВАЖНО! Запомните, что свойство [[Scope]] устанавливается по тому месту, где функция была объявлена, а не вызвана, именно поэтому код ниже выведет число 3, а не 5, как некоторые могли подумать.

bar b = 2;
function x(a) <
alert(a + b);
>

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

Читайте также:  Последние списания билайн номер

Как я уже говорил, объект LexicalEnvironment уничтожается каждый раз после выполнения функции и создается снова при повторном вызове. Однако что, если мы хотим сохранить эти данные? Т.е. мы хотим, чтобы все, что записано в LexicalEnvironment сейчас, сохранилось и было использовано при следующих вызовах? Именно для этого и существуют замыкания.

var func = greeting(‘Николай’);
greeting = null;
func();

Давайте посмотрим, что мы сделали. Сначала мы создаем функцию greeting, в которую передается имя. В функции создается объект LexicalEnvironment, где создается свойство(наша локальная переменная) name и ей присваивается имя "Николай". А теперь важно: мы возвращаем из функции другую функцию, внутри которой выводим через alert переменную name. Дальше мы присваиваем переменной func значение, возвращенное из функции greeting, а это значение — наша функция, которая выводит имя. Теперь мы greeting присваиваем null, т.е. мы просто уничтожаем нашу функцию greeting, однако, когда мы вызовем func, то увидим значение переменной name("Николай") функции greeting. Как такое возможно, скажете вы? А очень просто. Все дело в том, что наша возвращаемая функция также имеет свойство [[Scope]], которое ссылается на внешнюю область видимости, а эта внешняя область видимости в нашем случае — объект LexicalEnvironment нашей функции greeting. Поэтому, несмотря на то, что мы удалили нашу функцию greeting, объект LexicalEnvironment не удалился и остался в памяти, и он будет оставаться в памяти до тех пор, пока на него будет хотя бы одна ссылка. У нас эта ссылка — наша возвращаемая функция, которая использует переменную name этого объекта LexicalEnvironment.

Итак, давайте теперь дадим определение тому, что такое замыкание.

Замыкание — функция вместе со всеми переменными, которые ей доступны.

Что же, статья получилась довольно объемная, но это только потому, что я попытался как можно подробнее описать весь процесс работы замыкания. На закрепление хочу привести простой пример — счетчик с использованием только что изученной темы. Пожалуйста, разберитесь с кодом и напишите в комментариях, как и почему он работает. Если вы чего-то не поняли, вы также можете задать вопрос. Спасибо за внимание!

function makeCounter() <
var currentCount = 0;

return function() <
currentCount++;
return currentCount;
>;
>

var counter = makeCounter();
counter();
counter();
alert(counter()); // 3

Замыкания. Про них многие слышали, некоторые читали, все их использовали, но никто не понимает. Пришла пора исправить это досадное недоразумение.

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

Три кита js-замыканий

Замыкания в JavaScript основываются на трех глобальных концепциях:

  1. контексты выполнения кода;
  2. области видимости переменных;
  3. возможность сделать одну функцию аргументом другой.

Глобальный контекст и стек выполнения

Когда js-программа только начинает свою работу, в ней еще нет ни переменных, ни функций, ни одного замыкания – ничего. Один лишь чистый глобальный контекст выполнения. На этом не паханом поле программист обладает полной свободой действий.

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

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

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

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

Контексты функций

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

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

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

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

Любая функция что-то возвращает, необязательно явно. Даже если в ней отсутствует команда return , родителю будет возвращено значение undefined . Что с ним делать – решит уже сам контекст вызова. Текущая локальная область будет уничтожена вместе со всеми своими переменными и функциями.

Чтобы досконально разобраться в концепции контекстов выполнения кода, нужно шаг за шагом пройти весь путь js-интерпретатора от начала до конца программы. Для примера подойдет очень простой код, в котором тем не менее происходит создание и вызов функции.

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

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

По следам локальных областей

1. Строка 1. Инструкция let a инициализирует первую глобальную переменную a , которая изначально равна undefined .
2. Присваивание переменной a значения 3.
3. Строка 2. Объявление функции addTwo в глобальном контексте.
4. Строки со 2 по 5 относятся к функции. В данный момент они просто пропускаются интерпретатором без анализа и выполнения.

5. Строка 6. Инициализация еще одной глобальной переменной b . На данный момент b = undefined .
6. Затем обработчик видит инструкцию присваивания. Чтобы выполнить ее, ему необходимо рассчитать правую часть выражения. Там находится вызов функции addTwo с входящим аргументом a .
7. Интерпретатор осматривает текущий глобальный контекст. Нужная функция находится на строке 2, а аргумент обнаруживается в самом начале программы ( a = 3 ). Все готово, можно запускать функцию.
8. Запуск сопровождается созданием нового контекста выполнения и переходом в него. Все дальнейшие действия осуществляются уже внутри локальной области addTwo . Не следует забывать, что эта функция в итоге должна сформировать некоторое значение и вернуть его в глобальный контекст.

Читайте также:  Магнитола не видит файлы на флешке

8.1. Строка 2. Прежде всего, происходит инициализация параметра x и присвоение ему значения 3. Это первая локальная переменная области addTwo .
8.2. Строка 3. Создание в текущем контексте переменной result и занесение в нее числа 5 (результат сложения x + 2). Схема работы программы сейчас выглядит так:

8.3. Строка 4. Встретив завершающую команду, интерпретатор ищет переменную result . Она обнаруживается в текущем контексте на предыдущей строке. Таким образом, в глобальную область выполнения будет возвращено значение 5.

9. Сделав все, что полагается, обработчик с чистой совестью разрушает и удаляет из стека ненужный больше контекст функции addTwo вместе с переменными x и result .
10. Действие вновь возвращается в глобальную область на строку 6, где переменной b присваивается полученное из функции значение 5.

11. Строка 7. Здесь просто выводится на консоль для проверки результат работы программы.

Казалось бы, такая маленькая программа в 7 строк, а сколько событий!

Теперь понятно, что контекст выполнения – это просто актуальное на данный момент окружение кода. К нему относятся, например, входящие параметры и локальные переменные функции.

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

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

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

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

Замыкания активно эксплуатируют области видимости, поэтому следует уделить этой концепции особо пристальное внимание. Для полного осознания пройдем еще раз следом за интерпретатором по простой программе.

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

Сказ о том, как JavaScript переменную искал

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

На шестой строчке события начинают, наконец, развиваться.

1. Новая переменная multiplied получает стартовое значение undefined .
2. Обработчик видит операцию присваивания и вызов multiplyThis с правой стороны от знака = . Он отправляется на поиски этой функции, находит ее в текущем глобальном контексте и вызывает с аргументом 6.
3. Создается контекст multiplyThis , в котором сразу же инициализируется входящий параметр n = 6 .
4. Строка 3. Создается еще одна локальная переменная result со значением undefined .
5. Чтобы осуществить присваивание, интерпретатору нужно найти значения n и factor. С первым проблем не возникает: оно лежит в текущем контексте выполнения и равно 6.
6. Но factor по-прежнему не найден. Без него ничего не выйдет, неужели все было напрасно?

Обработчик кода обращается к родительскому контексту с просьбой выдать переменную и получает то, что хотел. Теперь можно умножить два значения и записать результат.
7. Функция завершается инструкцией return , возвращаемое значение равно 12, локальная область multiplyThis разрушается вместе с переменными n и result . А вот factor остается, так как он лежит в родительском контексте.

Дальше все просто: в multiplied записывается то, что вернула функция, и переменная выводится на консоль.

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

Функция в функции

Замыкания уже очень-очень близко, осталось лишь рассмотреть функциональную матрешку JavaScript, на которой все и основано.

Функции из примеров выше возвращали простое число. Это не очень интересно. Почему бы не вернуть из функции другую функцию? Тем более, язык позволяет и даже одобряет подобные начинания.

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

Сюжет закручивается на 9 строке при вызове функции createAdder .

1. Обработчик создает новую локальную область createAdder . Входящих параметров, требующих инициализации, у функции нет.
2. В текущем контексте объявляется переменная addNumbers .
3. Контекст завершает свою работу, возвращая описание функции.

Здесь следует сделать акцент на том, что возвращается только функциональное описание. Сама addNumbers будет разрушена вместе с локальной областью выполнения.
4. Теперь в adder записана функция, следовательно, ее можно вызвать. Что и делает программа на 10 строке.
5. Ожидаемо создается новая область adder , внутри которой инициализируются входящие аргументы a = 7 и b = 8 .
6. В новую локальную переменную result записывается результат их сложения, который и возвращается, когда функция отработает.

Замыкания уже рядом

Три разобранных выше программы – достаточный фундамент для понимания замыканий в JavaScript. Они утверждают и объясняют 3 важные концепции языка, касающиеся функций:

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

Сами замыкания подробно разобраны во второй части статьи.

Ссылка на основную публикацию
Что такое ogg формат
Ogg — Dateiendung: .ogg, .oga, .ogv, .ogx MIME Type … Deutsch Wikipedia .ogg — Dateiendung .ogg, .oga, .ogv, .ogx MIME...
Что значит включена переадресация вызова когда звонишь
Что такое переадресация звонков? Что значит «Переадресация звонков»? Данная услуга позволяет всегда оставаться на связи, за счёт перенаправления исходящих звонков....
Что значит восьмиядерный процессор
Дизайн и эргономика важны для гаджетов, но в то же время каждый пользователь понимает, что сердцем любого электронного устройства являются...
Что такое pppoe соединение на роутере
PPPoE (англ. Point-to-point protocol over Ethernet ) — сетевой протокол канального уровня (второй уровень сетевой модели OSI) передачи кадров PPP...
Adblock detector