//reverse a string with recursion and a closure
function r(str){
var i = str.length-1,results=[],j=0;
function _r(str){
if(i===0){
return results.join('') + str[0];
}
console.log('i = ' + i);
results[j] = str[i];
i--,j++;
console.log('j = ' + j);
return _r(str);
}
return _r(str);
}
我对上述代码有两个问题:
str
是一个大字符串,那么这个实现比没有使用闭包的解决方案更慢/更多内存密集吗? 答案 0 :(得分:2)
是的,你不使用功能范例。
在你的情况下,你只是使用递归来循环,并且使用函数之外的变量完成处理。它与使用全局变量没什么不同(除了它们不是全局变量,而是外部函数的本地变量)。
要使用函数方法反转字符串,您应该考虑字符串的反向由last_char +(中间部分的反向)+ first_char组成。 该定义自然地扩展为递归函数...例如:
function rev(str) {
if (str.length < 2) {
// Empty string or a single char... reverse = input
return str;
} else {
return str[str.length-1] + rev(str.slice(1, -1)) + str[0];
}
}
这不使用明确的状态(因为您可能会注意到根本没有任何分配)。
如果您正在寻找尾部调用可优化版本,请考虑:
function rev(todo, done) {
if (todo === "") {
return done;
} else {
return rev(todo.slice(1), todo[0] + (done||""));
}
}
在这种情况下的想法是处理案例必须是return <recursive-call>
(在前面的例子中没有发生这种情况,因为递归的结果在返回之前向每一端添加了一个char)。
如果您的代码最终返回递归调用的未处理结果,则该函数可以进行尾调用优化,因为不需要堆栈空间。换句话说,递归调用变成了一个简单的循环。
最后这是另一个版本,不是纯粹的功能,但它看起来与你正在尝试的类似:
function rev(str) {
function rev1(v, i, j) {
if (i >= j) {
return v.join("");
} else {
var t=v[i]; v[i]=v[j]; v[j]=t;
return rev1(v, i+1, j-1);
}
}
return rev1(str.split(""), 0, str.length-1);
}
这不是纯函数,因为向量元素是交换的(你可以看到有赋值)但是使用尾调用可优化递归来进行循环。请注意,rev1
不是闭包而是函数(不捕获任何状态,也可以将其置于rev
之外)。