Рекурсия может потерпеть неудачу быстрее, так как бесконечно рекурсивная функция уничтожит стек, создав исключение, из которого программа может восстановиться, в то время как итеративное решение будет работать до тех пор, пока не будет остановлено внешним агентом.
Для кода, который будетпроизводить корректный вывод в данное время, основная стоимость рекурсии - это издержки вызова функции.Итеративные решения просто не имеют этого, поэтому стремятся выиграть в критически важном для производительности коде в языках, которые явно не оптимизируются для рекурсии.
Это определенно заметно в тестах, но если вы не пишете критичный для производительности код,Ваши пользователи, вероятно, не заметят.
В тестах на http://jsperf.com/function-call-overhead-test пытаются количественно оценить издержки вызова функций в различных интерпретаторах JS.Я бы собрал аналогичный тест, который явно тестирует рекурсию, если вы беспокоитесь.
Обратите внимание, что оптимизацию рекурсии с помощью хвостового вызова сложно сделать в EcmaScript 3.
Например,простая реализация свертывания массива в JavaScript:
function fold(f, x, i, arr) {
if (i === arr.length) { return x; }
var nextX = f(x, arr[i]);
return fold(f, nextX, i+1, arr);
}
нельзя оптимизировать хвостом, потому что вызов
fold(eval, 'var fold=alert', 0, [0])
будет eval('var fold=alert')
внутри тела fold
, вызываяказалось бы, хвостово-рекурсивный вызов fold
не является рекурсивным.
EcmaScript 5 изменил eval
, чтобы не вызывать его, кроме как через имя eval
, а строгий режим не позволяет eval
вводить локальные переменные, но оптимизация хвостового вызова зависит от способности статически определять, куда идет хвостовой вызов, что не всегда возможно в динамических языках, таких как JavaScript.