2015-04-12 12 views
5

Ich versuche, eine ziemlich einfache Javascript-Funktion zu schreiben, und Verhalten zu erfahren, verstehe ich nicht, wenn ich die Funktion iterieren.Problem mit dem Aufrufen einer JavaScript-Funktion zweimal

Ich habe das Problem auf die folgende Situation destilliert. Ich möchte eine Funktion schreiben, die als Eingabe ein Array verwendet, das aus Arrays von Arrays besteht, z. A = [[[1]]]. Ich kenne die Standardterminologie dafür nicht, deshalb werde ich das Hauptarray als "Level 0" bezeichnen, das Elemente enthält, die Arrays von "Level 1" sind. Ich werde sagen, dass die Level-1-Arrays aus Arrays von "Level 2" bestehen. Die Level-2-Arrays bestehen aus ganzen Zahlen.

Die Funktion hat die folgende, auf Eingabe A (a-Ebene-0-Array):

  1. ein leeres Array erstellen L;
  2. für jede Ebene 1 Array M in A
    • eine in M in jeder Ebene 2 Array zu jedem ganzzahligen Eintrag hinzufügen;
    • zwei Kopien von M-L
  3. Rückkehr L hinzuzufügen.

Hier ist mein Code:

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

Jetzt habe ich es testen:

var A = [[[1]]]; 

A = myFunc(A) 

Danach, ich A = [[[2]],[[2]]] bekommen, das ist, was ich erwarte. Allerdings nehme ich es wiederholen:

var A = [[[1]]]; 

A = myFunc(A); 

A = myFunc(A); 

Dann erwarte ich A = [[[3]],[[3]],[[3]],[[3]]] zu erhalten, sondern ich habe A = [[[4]],[[4]],[[4]],[[4]]].

Auf der anderen Seite, wenn ich myFunc([[[2]],[[2]]]) ausführen, bekomme ich die erwartete [[[3]],[[3]],[[3]],[[3]]].

Ich verstehe nicht, wo diese Diskrepanz herkommt.

+1

Das ist nicht das Problem. Die Funktion hat beim zweimaligen Aufruf nicht die gleichen Ergebnisse, lesen Sie die Frage erneut. Ich untersuche und ich habe eine Spur, glaube ich –

+1

Es ist wahrscheinlich ein referenzierter Wert vs eine kopierte. Probieren Sie A = JSON.parse (JSON.stringify (A)) zwischen Ihren A = myFunct (A) -Aufrufen aus. Ich kann nicht testen, ich bin auf meinem iPhone –

+1

@FlavienVolken ja das löst es, aber ich verstehe nicht, warum es hier versagt. : o –

Antwort

5

Das Problem ist die Zeile:

M[i][j]++; 

Knoten hält dies als Hinweis auf Ihre A der Scheibe, und man sieht es deutlich, wenn Sie dieses tun:

x = [[[1]]]; 
myFunc(x); 
myFunc(x); 
console.log(x); // ---> [[[3]]] 

Für eine flache Kopie Sie würde den JSON.parse(JSON.stringify()) Trick benutzen müssen, und Beweis, dass M das Problem ist; Hinzufügen dieser Zeile kurz nach M = A[a].slice(0); löst das Problem.

M = JSON.parse(JSON.stringify(M)) 

Mozillas Dokumentation über Array.prototype.slice():

Für Objektreferenzen (und nicht das eigentliche Objekt), in Scheiben schneiden Kopien Objekt Referenzen in das neue Array.Sowohl das ursprüngliche als auch das neue Array verweisen auf dasselbe Objekt auf . Wenn sich ein referenziertes Objekt ändert, sind die Änderungen für das neue und das ursprüngliche Array sichtbar.

Source

Aus diesem Grund, denn wenn man M[i][j] tun, ein Niveau, das Array noch tiefer außerhalb verwiesen wird.

0

Seit Tristan Foureur hat bereits darauf hingewiesen, was die Diskrepanz verursacht, ich wollte nur in hinzufügen, warum

var A = [[[1]]]; 

A = myFunc(A); 
A = myFunc(A); 

gibt ein anderes Ergebnis gegen

myFunc([[[2]],[[2]]]) 

Wenn myFunc([[[2]],[[2]]]) tun, was Sie tun im Grunde ist myFunc(new Array(new Array(new Array(2))),(new Array(new Array(2))))).

Also, wenn der V8-Motor

var M = A[a].slice(0); 

diese Linie erhöht würde es A[a].slice(0) als

new Array(new Array(new Array(2))),(new Array(new Array(2))))[a].slice(0) 

interpretieren und somit erhalten Sie 2 (aus dem neuen Array) jedes Mal, sie aufgerufen wird.

Das kann man sehen, wenn Sie die Funktion mit Protokollen prüfen:

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

Wenn Sie var M = A[a].slice(0); mit

var M = new Array(new Array(new Array(2))),(new Array(new Array(2))))[a].slice(0) 

ersetzen und ohne A durch die Funktion laufen, würden Sie [[[3]],[[3]],[[3]],[[3]]] sehen.

1

Wie andere schon erwähnt haben, ist der M.slice Aufruf nur eine flache Kopie. Sie haben auch gute Lösungen für eine Deepcopy gegeben. Ich schlage vor, dass Sie wirklich die Kopie überhaupt nicht tun müssen:

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