调用两次javascript函数的问题

时间:2015-04-12 20:33:50

标签: javascript arrays loops iteration

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

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

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

  1. 创建一个空数组L;
  2. {li>为M中的每个1级数组A
    • M;
    • 中的每个2级数组中的每个整数条目中添加一个
    • M的两份副本添加到L
  3. 返回L
  4. 这是我的代码:

    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]]]

    我不明白这种差异来自哪里。

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复制对象   引用到新数组中。原始阵列和新阵列都参考   对同一个对象。如果引用的对象发生更改,则更改为   对新的和原始数组都可见。

Source

这就是为什么,因为当你执行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]]]