Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Косвенная рекурсия в Javascript (https://javascript.ru/forum/misc/30029-kosvennaya-rekursiya-v-javascript.html)

hrundel 21.07.2012 18:09

Косвенная рекурсия в Javascript
 
Пытаюсь разобраться в рекурсии. Почему когда я пишу так:
<script type="text/javascript">
function recursMe(param) {
     if (param < 0) {   //base case
          return -1;
     }
     else {

          //some code here
          recursMe(param);
     }
}
recursMe(10);

	</script>

или так (используя косвенную рекурсию):
<script type="text/javascript">
function recursMe(param) {
     if (param < 0) {   //base case
          return -1;
     }
     else {

          //some code here
          //recursMe(param);
		recursMe2(param);
     }
}
function recursMe2(param)
{
	 recursMe(param);
}
recursMe(10);

	</script>

во всех браузерах я имею ошибку примерно такого характера:
Хром: Uncaught RangeError: Maximum call stack size exceeded
ie: Stack overflow at line:135


Когда я делаю косвенную рекурсию через setTimeout() так:
<script type="text/javascript">
function recursMe(param) {
     if (param < 0) {   //base case
          return -1;
     }
     else {

          //some code here
          setTimeout("recursMe(" + param + ")", 1);
     }
}
recursMe(10);

	</script>

браузеры не выдают ошибку, хотя происходит та же ситуация: функция recursMe() вызывается много раз подряд. Почему так происходит?

nerv_ 21.07.2012 18:28

hrundel, http://css-live.ru/javascript/javasc...rekursiya.html - не самая хорошая статья.

Что проиходит в первом коде, приведенном Вами? Подсказка:
Цитата:

Сообщение от hrundel
Хром: Uncaught RangeError: Maximum call stack size exceeded


Лично я бы не стал разбирать рекурсию на таких отвлеченных примерах. Для начала попробуйте зарыться в DOM.

vadim5june 21.07.2012 18:43

Цитата:

Сообщение от hrundel (Сообщение 190537)
браузеры не выдают ошибку, хотя происходит та же ситуация: функция recursMe() вызывается много раз подряд. Почему так происходит?

стек не переполняется-потому что SEtTimeout выполняется в глобальном контексте
там же ошибка переполнения стека
Stack overflow at line:135
с setTimiout у Вас нерекурсивное обращение к функции

hrundel 22.07.2012 17:59

Цитата:

Сообщение от vadim5june
стек не переполняется-потому что SEtTimeout выполняется в глобальном контексте
там же ошибка переполнения стека
Stack overflow at line:135
с setTimiout у Вас нерекурсивное обращение к функции

А как обычному человеку определять, когда рекурсивно обращение к функции, а когда нерекурсивное? Я считаю, что косвенная рекурсия всегда вызвана одним и тем же - функция вызывает саму себя через цепочку других функций. Здесь такая ситуация и во втором примере и в третьем, но результат разный.
Что за глобальный контекст у setTimeout()? Как он может влиять на переполнение стека?

B@rmaley.e><e 22.07.2012 18:06

Цитата:

Сообщение от hrundel
Здесь такая ситуация и во втором примере и в третьем

Наглая ложь. Рекурсия имеет место, когда внутри функции нужно получить результат её вызова от других (впрочем, не обязательно отличных от текущих) аргументов. В случае с setTimeout никаких результатов никто дожидаться не будет. JS где-то у себя внутри сделает пометку "через сколько-то мс запустить такую-то функцию" и спокойно продолжит исполнение.

vadim5june 22.07.2012 19:13

Цитата:

Сообщение от hrundel (Сообщение 190728)
Я считаю, что косвенная рекурсия всегда вызвана одним и тем же - функция вызывает саму себя через цепочку других функций. Здесь такая ситуация и во втором примере и в третьем, но результат разный.
Что за глобальный контекст у setTimeout()? Как он может влиять на переполнение стека?

когда вызывается setTimeout эта цепочка прерывается
В чем смысл рекурсии-когда функция вызывает саму себя то текущее состояние записывается в стек -потому что потом должны быть выполнены команды которые стоят после операции вызова
Это обычно например обход дерева DOM
А когда выполняется команда setTimeout записи в стек не будет потому что seTimeout асинхронная команда
Цитата:

Сообщение от hrundel (Сообщение 190728)
Что за глобальный контекст у setTimeout()? Как он может влиять на переполнение стека?

Вы не знаете разве что функции записанные в setTimeout выполняются в глобальном контексте window а не в контексте объекта вызывающей функции

oneguy 24.07.2012 05:27

Цитата:

Сообщение от vadim5june
Вы не знаете разве что функции записанные в setTimeout выполняются в глобальном контексте window а не в контексте объекта вызывающей функции

А вот и неправда :) Функции, записанные в setTimeout выполняются в том контексте, в которым они определены. Пример:
var f=function () {
  var b=1;
  return function () {
    alert(b);
  };
}();
setTimeout(f, 0);

vadim5june 24.07.2012 07:56

Цитата:

Сообщение от oneguy (Сообщение 191141)
А вот и неправда :) Функции, записанные в setTimeout выполняются в том контексте, в которым они определены.
[/JS]

я то имел ввиду вызывающую функцию-это функция где сам setTimout вызывается
у Вас в примере setTimout вызывается в глобальном контексте

Функция выполняется в другом контексте, отличном от контекста, в котором задается setTimeout.
При этом значение this = window, поэтому о передаче правильного this надо позаботиться отдельно.

http://javascript.ru/setTimeout
правда контекст к рекурсии никакого отношения не имеет-а имеет значение асинхронность setTimout
Этот метод выполняет код(или функцию), указанный в первом аргументе, асинхронно, с задержкой в delay миллисекунд.
я так понимаю что даже если указать delay=0 все равно метод будет выполнятся асинхронно

hrundel 24.07.2012 16:58

Цитата:

Сообщение от oneguy (Сообщение 191141)
А вот и неправда :) Функции, записанные в setTimeout выполняются в том контексте, в которым они определены. Пример:
var f=function () {
  var b=1;
  return function () {
    alert(b);
  };
}();
setTimeout(f, 0);

Странный пример :) Непонятно, как он что-то может доказать? По-моему, очевидный результат, равный '1'. Что-то ваша мысль до конца не раскрыта.

oneguy 24.07.2012 23:16

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


Часовой пояс GMT +3, время: 12:40.