我正在研究一个需要递归函数的问题,并注意到嵌套执行似乎正在修改父代的参数:
var foo = function(ar) {
console.log('Calling function - Array: ' + ar.toString());
if(ar.length > 1){
var ele = ar.pop();
foo(ar);
console.log('Function recursion ends - Array: ' + ar.toString() + ' Popped: ' + ele);
return;
} else {
console.log('Function ends - Array: ' + ar.toString());
return;
}
}
foo([1,2,3]);
输出(缩进矿):
/* Calling function - Array: 1,2,3 Calling function - Array: 1,2 Calling function - Array: 1 Function ends - Array: 1 Function recursion ends - Array: 1 Popped: 2 Function recursion ends - Array: 1 Popped: 3 <-- What happened to 2? */
这看起来很奇怪 - 因为我用[1,2,3]
调用了函数,我希望函数的第一次迭代仍然保持在ar
和{{}之间提供给它的所有元素。 {1}} - 但是当函数结束时,只有ele
保留在提供的数组中 - 1
发生了什么?嵌套执行2
是否超出了第一个执行的变量?
我对JavaScript中函数作用域的理解会说传递给函数的变量只能在本地修改它们,而不能将它们导出回全局/父作用域,如下所示:
pop
但递归函数的输出似乎挑战了这种理解。
如何防止这些嵌套执行修改父参数以恢复丢失的var bar = 'bar';
function doBar(bar){
bar = 'foo';
}
doBar(bar);
console.log(bar); //Outputs 'bar';
?我对JavaScript中作用域的理解是错误的吗?
在打开这个问题之前,我在抓住吸管的可怜尝试中尝试在闭包中执行该功能:
2
但是我得到了与没有使用闭包相同的结果 - 我怀疑是因为我明确地传递了var foo = function(ar) {
console.log('Calling function - Array: ' + ar.toString());
if(ar.length > 1){
var ele = ar.pop();
(function(foo, ar){
foo(ar);
})(foo, ar)
console.log('Function recursion ends - Array: ' + ar.toString() + ' Popped: ' + ele);
return;
} else {
console.log('Function ends - Array: ' + ar.toString());
return;
}
}
和ar
,这与没有闭包没什么不同。
答案 0 :(得分:1)
Array.prototype.pop()
是一个可变操作。当您以递归方式调用foo
时,该可变操作在调用范围内仍然有效。范围没有任何奇怪的事情,只是你可能期望foo
内的操作不能修改你给它的参数的内部。数组通过引用传递,这意味着参数将引用调用范围所执行的相同数组。
相反,您可以致电arr.slice(0, -1)
。这将返回数组的浅表副本,而不是修改现有数组。它将改变你获取数组最后一个索引的方式。
var foo = function(ar) {
console.log('Calling function - Array: ' + ar.toString());
if(ar.length > 1){
var ar2 = ar.slice(0, -1);
foo(ar2);
console.log('Function recursion ends - Array: ' + ar2.toString() + ' Popped: ' + ar.slice(-1));
return;
} else {
console.log('Function ends - Array: ' + ar.toString());
return;
}
}
foo([1,2,3]);
答案 1 :(得分:0)
正如@ 4castle建议的那样,如果你想在每次迭代时拥有更持久的数组视图,你可以用slice()克隆ar。或者,您也可以重新设计函数foo(),以便有更多空间使用&#34; current&#34; ar和ele。
var foo = function(ar) {
console.log('Given Array: ' + ar.toString());
if(ar.length === 0){
console.log('recursion ended');
return;
}
var ele = ar.pop();
console.log('Array Now: ' + ar.toString() + ' After Popping: ' + ele);
console.log(" ");
foo(ar);
}
foo([1,2,3]);
&#13;