繁体   English   中英

调用两次javascript函数的问题

[英]issue with calling a javascript function twice

我正在尝试编写一个相当简单的Javascript函数,并且在迭代函数时遇到我不理解的行为。

我已将问题归结为以下情况。 我想编写一个函数,将一个由数组数组组成的数组作为输入,例如A = [[[1]]] 我不知道这个的标准术语,所以我将主数组称为“级别0”,其中元素是“级别1”的数组。 我会说1级数组由“2级”数组组成。 2级数组由整数组成。

该函数在输入A (0级数组)上执行以下操作:

  1. 创建一个空数组L ;
  2. 对于A每个1级数组M
    • M中的每个2级数组中的每个整数条目中加1;
    • 将两份M加到L
  3. 返回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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM