Закрытие Javascript, возвращающее рекурсивную функцию
Я новичок в Javascript и функциональных парадигмах. Мне действительно нравится использовать закрытие, чтобы безопасно хранить маленькие кусочки состояния в закрытой области видимости. Это освежающее изменение от песни и танца поклонения классу на Яве.
Я написал следующий код с намерением вывести на консоль 0-9. Это работает, но я удивлен, что это делает.
Я не понимаю как next
ссылается на возвращенную функцию для рекурсивного next()
вызов! Связано ли это со свойством "позднего связывания" Javascript?
var next = (function() { // begin stateful wrapper function
var current = -1;
return function() { // begin returned function
current += 1;
if (current < 10) {
console.log(current);
next(); // recursive call
} else {
return;
}
}; // end returned function
})(); // immediately call wrapper function
next(); // call returned function to generate output
Как во время выполнения рекурсивный вызов next() уже ссылается на возвращаемую функцию?
Где можно прочитать о деталях того, что здесь происходит?
(Выход:)
0
1
2
3
4
5
6
7
8
9
2 ответа
Возможно, вы смущены самой внешней функцией, которая вызывается немедленно. Это служит только для защиты current
в переменной области. Если мы устраняем это, это, вероятно, яснее.
var current = -1;
var next = function() {// This is what would have been returned in the original
current += 1;
if (current < 10) {
console.log(current);
next(); // recursive call
} else {
return;
}
};
next();
Теперь у вас есть то же, что и оригинальный код, за исключением того, что current
не в своей сфере. Как видите, функция просто назначена next
переменная.
Это именно то, что происходит в оригинале, за исключением того, что в оригинале внешняя функция существует и немедленно вызывается. Эта внешняя функция является одноразовой и не назначается next
хотя его return
значение
У JavaScript нет пока блочной области видимости, но если он есть, подумайте, что он похож на это:
var next;
{ // Create a (fictional) variable scope that has `current` and the function
var current = -1;
next = function() {
current += 1;
if (current < 10) {
console.log(current);
next(); // recursive call
} else {
return;
}
};
}
next();
Но поскольку JS не имеет области видимости блока, а только области действия функции, нам нужно эмулировать это с помощью функции.
Мы можем немного подправить оригинал, чтобы он выглядел похожим.
var next;
(function() { // Create a variable scope that has `current` and the function
var current = -1;
next = function() {
current += 1;
if (current < 10) {
console.log(current);
next(); // recursive call
} else {
return;
}
};
}());
next();
Как во время выполнения рекурсивный вызов next() уже ссылается на возвращаемую функцию?
Когда вы вызываете функцию, чтобы построить функцию, которая определяет next
(в соответствии с })(); // immediately call wrapper function
), вы только возвращаете функцию (функции - это просто другой тип данных в JavaScript, пока не будет вызван), которая ссылается на глобальный next
переменная, еще не используя ее. Следующий шаг (next();
) начинает процесс и к тому времени внутренний next
ссылка может найти глобальный next
определение.
AFAIU, терминология "позднего связывания" имеет тенденцию иметь отношение к динамическому значению свойств, с this
будучи особенно важным.
Доступ к next
опаздывает здесь в том смысле, что функция не должна быть доступна во время определения, а скорее во время вызова (хотя переменная next
функция уже известна во время определения для внутренней функции, но ее значение undefined
в это время; переменная была бы известна JavaScript, даже если бы ВСЕ ваш код был внутри функции и var
были установлены в конце блока).
(Небольшое примечание (которое можно игнорировать, если в нем слишком много информации): Хорошая практика (и необходимая для "строгого режима") - определять глобальные переменные, такие как next
с var
как вы сделали. JavaScript будет обрабатывать ссылки на переменные как глобальные var
используется в этой области, но, как уже упоминалось, даже если весь ваш код был внутри функции и next
была локальной переменной, ее определение с var
позволяет обнаруживать эту переменную в любом месте внутри замыкания, даже внутри вложенных функций (в отличие от this
это еще одна банка глистов).)
Где можно прочитать о деталях того, что здесь происходит?
Вы можете найти это полезным: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
ОБНОВИТЬ
В ответ на комментарий:
В JavaScript...
- Если переменная функции (или любая переменная) определяется с помощью
var
это признаетсяundefined
(не как ошибка типа) в этой области (включая случай, когда она определена в верхней части, глобальная область), пока не будет выполнено присваивание, чтобы дать ему значение функции (чтобы его можно было выполнить или передать). Аналогично с назначениями на существующие объекты, такие какwindow.myFunc = function () {};
, - Если функция только что объявлена без
var
лайкfunction myName () {}
, он сразу доступен везде в этой области, до или после объявления. Как сvar
объявления функций, они также могут рассматриваться как данные, а функция передается как данные, например, для обратных вызовов. - Если переменная функции определена как переменная, но без
var
существующий с таким именем в любом месте вплоть до глобальной области видимости, например,myGlobal = function () {};
даже это не приведет к ошибкам (и будет работать как #1 выше), если не действует "строгий режим", и в этом случае он выдаст ошибку.