2015-04-12 57 views
5

我想寫一個相當簡單的Javascript函數,並體驗行爲我不明白當我迭代函數。問題與調用一個JavaScript函數兩次

我已將問題歸結爲以下情況。我想編寫一個函數,它將輸入一個由數組數組組成的數組,例如, A = [[[1]]]。我不知道這個標準術語,所以我將把主數組稱爲「級別0」,其中的元素是「級別1」的數組。我會說1級數組由「級別2」的數組組成。 2級數組由整數組成。

功能將執行以下操作,輸入A(0級陣列):

  1. 創建一個空數組L;
  2. 爲每個級別1陣列MA
    • 添加一個到每個級別2陣列中M在每個整數條目;
    • 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]]]

我不明白這種差異來自何處。

+1

這不是問題所在。被調用兩次的函數沒有相同的結果,請再次閱讀他的問題。我正在調查,我得到了領導,我認爲 –

+1

它可能是一個參考值與複製值。在A = myFunct(A)調用之間嘗試使用A = JSON.parse(JSON.stringify(A))。我無法測試我在我的iPhone上 –

+1

@FlavienVolken是的,它確實解決了它,但我不明白爲什麼它在這裏失敗。 :o –

回答

5

的問題是該行:

M[i][j]++; 

節點保持這是你的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()

對象引用(而不是實際的對象),片拷貝對象 引用到新陣列。原始陣列和新陣列都將 指向同一個對象。如果引用的對象發生更改,則更改爲 對於新數組和原始數組均可見。

Source

這就是爲什麼,因爲當你做M[i][j],該陣列更深一層仍然引用之外。

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 = new Array(new Array(new Array(2))),(new Array(new Array(2))))[a].slice(0) 

更換var M = A[a].slice(0);並通過無A功能運行時,你會看到[[[3]],[[3]],[[3]],[[3]]]

這可以,如果你檢查與日誌功能可以看出。

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);