2015-04-12 9 views
5

Sto provando a scrivere una funzione Javascript abbastanza semplice, e sperimentando un comportamento che non capisco quando iterare la funzione.problema con la chiamata di una funzione javascript due volte

Ho distillato il problema fino alla seguente situazione. Voglio scrivere una funzione che prenda come input un array costituito da matrici di array, ad es. A = [[[1]]]. Non conosco la terminologia standard per questo, quindi mi riferirò all'array principale come "livello 0", che ha elementi che sono matrici di "livello 1". Dirò che gli array di livello 1 consistono in array di "livello 2". Le matrici di livello 2 sono costituite da numeri interi.

La funzione fa seguito, sull'ingresso A (un array di livello 0):

  1. creare un array vuoto L;
  2. per ciascun livello 1 matrice M in A
    • aggiungere uno a ciascuna voce integer in ogni matrice livello 2 M;
    • aggiungono due copie di M al L
  3. ritorno L.

Ecco il mio codice:

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

Ora provarlo:

var A = [[[1]]]; 

A = myFunc(A) 

Dopo questo, ho A = [[[2]],[[2]]], che è quello che mi aspetto. Tuttavia, supponiamo che io iterare che:

var A = [[[1]]]; 

A = myFunc(A); 

A = myFunc(A); 

Poi mi aspetto di ottenere A = [[[3]],[[3]],[[3]],[[3]]], ma invece ho A = [[[4]],[[4]],[[4]],[[4]]].

D'altra parte se corro myFunc([[[2]],[[2]]]), ottengo il previsto [[[3]],[[3]],[[3]],[[3]]].

Non capisco da dove provenga questa discrepanza.

+1

Questo non è il problema. La funzione chiamata due volte non ha gli stessi risultati, legge di nuovo la sua domanda. Sto indagando e ho un vantaggio credo che sia –

+1

Probabilmente è un valore di riferimento rispetto a uno copiato. Prova A = JSON.parse (JSON.stringify (A)) tra le tue chiamate A = myFunct (A). Non riesco a testare che io sia sul mio iPhone –

+1

@FlavienVolken sì che lo risolve ma non capisco perché sta fallendo qui. : o –

risposta

5

Il problema è la linea:

M[i][j]++; 

nodo mantiene questo come un riferimento alla fetta del vostro A, e si vede chiaramente quando si esegue questa operazione:

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

Per una copia voi Dovrei usare il trucco JSON.parse(JSON.stringify()) e dimostrare che M è il problema; l'aggiunta di questa riga subito dopo lo M = A[a].slice(0); risolve il problema.

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

documentazione di Mozilla su Array.prototype.slice():

Per riferimenti a oggetti (e non l'oggetto reale), le copie oggetto porzione riferimenti nel nuovo array.Sia l'array originale che quello nuovo fanno riferimento allo allo stesso oggetto. Se un oggetto di riferimento cambia, le modifiche sono visibili sia per gli array nuovi che per quelli originali.

Source

Ecco perché, perché quando si fa M[i][j], l'array un livello più profondo è ancora riferimento al di fuori.

0

Dal Tristan Foureur ha già sottolineato che cosa ha causato la discrepanza, volevo solo aggiungere perché

var A = [[[1]]]; 

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

dà un risultato diverso rispetto a

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

Nel fare myFunc([[[2]],[[2]]]), quello che in pratica stanno facendo myFunc(new Array(new Array(new Array(2))),(new Array(new Array(2))))).

Così, quando il motore V8 eleva questa linea

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

sarebbe interpretare A[a].slice(0) come

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

e, quindi, si ottiene 2 (dal new Array) ogni volta che viene chiamato.

Questo può essere visto se si esamina la funzione con i registri:

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

Se si sostituisce var M = A[a].slice(0); con

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

e passare per la funzione senza A, si vedrebbe [[[3]],[[3]],[[3]],[[3]]].

1

Come altri hanno già menzionato il problema è che la chiamata M.slice ha fatto solo una copia superficiale. Hanno anche fornito buone soluzioni su come eseguire una deep chap. Suggerirei che non hai davvero bisogno di fare la copia:

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