我正在尝试编写一个相当简单的Javascript函数,并且在迭代函数时遇到我不理解的行为。
我已将问题归结为以下情况。我想编写一个函数,它将一个由数组数组组成的数组作为输入,例如A = [[[1]]]
。我不知道这个的标准术语,所以我将主数组称为“级别0”,其中元素是“级别1”的数组。我会说1级数组由“2级”数组组成。 2级数组由整数组成。
该函数在输入A
(0级数组)上执行以下操作:
L
; M
中的每个1级数组A
M
; M
的两份副本添加到L
L
。这是我的代码:
function myFunc(A){
var L = [];
for(var a=0; a<A.length; a++){
var M = A[a].slice(0);
for(var i=0; i<M.length; i++){
for(var j=0; j<M[i].length; j++){
M[i][j]++;
}
}
for(var s=0; s<2; s++){
var N = M.slice(0);
L.push(N);
}
}
return(L);
}
现在我测试一下:
var A = [[[1]]];
A = myFunc(A)
在此之后,我得到A = [[[2]],[[2]]]
,这是我的期望。但是,假设我迭代它:
var A = [[[1]]];
A = myFunc(A);
A = myFunc(A);
然后我希望获得A = [[[3]],[[3]],[[3]],[[3]]]
,但我得A = [[[4]],[[4]],[[4]],[[4]]]
。
另一方面,如果我运行myFunc([[[2]],[[2]]])
,我会得到预期的[[[3]],[[3]],[[3]],[[3]]]
。
我不明白这种差异来自哪里。
答案 0 :(得分:5)
问题在于:
M[i][j]++;
Node将此作为对A切片的引用,并在执行此操作时清楚地看到它:
x = [[[1]]];
myFunc(x);
myFunc(x);
console.log(x); // ---> [[[3]]]
对于浅拷贝,您必须使用JSON.parse(JSON.stringify())
技巧,并证明M是问题;在M = A[a].slice(0);
解决问题之后添加此行。
M = JSON.parse(JSON.stringify(M))
Mozilla关于Array.prototype.slice()
的文档:
对于对象引用(而不是实际对象),slice复制对象 引用到新数组中。原始阵列和新阵列都参考 对同一个对象。如果引用的对象发生更改,则更改为 对新的和原始数组都可见。
这就是为什么,因为当你执行M[i][j]
时,更深层次的数组仍在外面引用。
答案 1 :(得分:1)
正如其他人已经提到的那样,问题是M.slice
来电只做了一个浅薄的副本。他们也为如何进行深度检查提供了很好的解决方案。我建议你根本不需要复制副本:
var L = [];
for (var iLevel1 = 0; iLevel1 < A.length; iLevel1++)
{
for (var iLevel2 = 0; iLevel2 < A[iLevel1].length; iLevel2++)
{
for (var iLevel3 = 0; iLevel3 < a[iLevel1][iLevel2].length; iLevel3++)
L.push(a[iLevel1][iLevel2][iLevel3] + 1);
}
}
return L.concat(L);
答案 2 :(得分:0)
由于Tristan Foureur已经指出导致差异的原因,我只是想补充一下为什么
var A = [[[1]]];
A = myFunc(A);
A = myFunc(A);
给出了与
不同的结果myFunc([[[2]],[[2]]])
执行myFunc([[[2]],[[2]]])
时,您基本上做的是myFunc(new Array(new Array(new Array(2))),(new Array(new Array(2)))))
。
所以当V8发动机提升此线时
var M = A[a].slice(0);
它会将A[a].slice(0)
解释为
new Array(new Array(new Array(2))),(new Array(new Array(2))))[a].slice(0)
因此每次调用时都会获得2(来自新数组)。
如果用日志检查函数,可以看到这一点:
function myFunc(A){
var L = [];
console.log("A is"+ JSON.stringify(A));
for(var a=0; a<A.length; a++){
var M = A[a].slice(0);
console.log("M is"+ JSON.stringify(M) + " while A is" +JSON.stringify(A),a);
for(var i=0; i<M.length; i++){
for(var j=0; j<M[i].length; j++){
M[i][j]++;
}
}
for(var s=0; s<2; s++){
var N = M.slice(0);
L.push(N);
console.log("L.push:"+ JSON.stringify(N));
}
}
console.log("the end" + JSON.stringify(L), JSON.stringify(A));
return(L);
}
var A = [[[1]]];
A = myFunc(A);
A = myFunc(A);
var t = myFunc([[[2]],[[2]]]);
如果用
替换var M = A[a].slice(0);
var M = new Array(new Array(new Array(2))),(new Array(new Array(2))))[a].slice(0)
并在没有A的情况下运行该功能,您会看到[[[3]],[[3]],[[3]],[[3]]]
。