[英]issue with calling a javascript function twice
我正在尝试编写一个相当简单的Javascript函数,并且在迭代函数时遇到我不理解的行为。
我已将问题归结为以下情况。 我想编写一个函数,将一个由数组数组组成的数组作为输入,例如A = [[[1]]]
。 我不知道这个的标准术语,所以我将主数组称为“级别0”,其中元素是“级别1”的数组。 我会说1级数组由“2级”数组组成。 2级数组由整数组成。
该函数在输入A
(0级数组)上执行以下操作:
L
; A
每个1级数组M
M
中的每个2级数组中的每个整数条目中加1; 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]]]
。
我不明白这种差异来自何处。
问题是这条线:
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 = A[a].slice(0);
解决了这个问题。
M = JSON.parse(JSON.stringify(M))
Mozilla关于Array.prototype.slice()
的文档:
对于对象引用(而不是实际对象),slice将对象引用复制到新数组中。 原始数组和新数组都引用相同的对象。 如果引用的对象发生更改,则更改对新的和原始数组都可见。
这就是为什么,因为当你做M[i][j]
,更深层次的数组仍在外面引用。
正如其他人已经提到的那样,问题是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);
由于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]]]
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.