Recursion may fail faster since an infinitely recursive function will blow out the stack producing an exception that the program can recover from, while an iterative solution will run until stopped by an outside agent.
For code that will produce a valid output given time, the main cost of recursion is function call overhead. Iterative solutions simply don't have this, so tend to win in performance critical code in languages that don't explicitly optimize for recursion.
It's definitely noticeable in benchmarks, but unless you're writing performance critical code, your users probably won't notice.
The benchmarks at http://jsperf.com/function-call-overhead-test try to quantify function call overhead in various JS interpreters. I would put together a similar benchmark that explicitly tests recursion if you're worried.
Note that tail-call recursion optimization is difficult to do correctly in EcmaScript 3.
For example, a simple implementation of array folding in 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);
}
cannot be tail-optimized because the call
fold(eval, 'var fold=alert', 0, [0])
would eval('var fold=alert')
inside the body of fold
, causing the seemingly tail-recursive call to fold
to not be actually recursive.
EcmaScript 5 changed eval
to not be callable except via the name eval
, and strict mode prevents eval
from introducing local variables, but tail-call optimization depends on the ability to statically determine where a tail-call goes which is not always possible in dynamic languages like JavaScript.