Question:
To generate the following array:
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
Consider the following code for building a matrix with equal rows:
var linha = [1, 2, 3, 4];
var matriz = [linha, linha, linha ];
matriz[3] = linha ; // outra alternativa
matriz.push(linha); // mais outro modo
It seems logical to use this code to generate the array. But we have a catch, we are adding elements by reference in Array matriz
.
if we try
matriz[0].push(); // retirar o elemento na posição A[0][4]
matriz[1][1] = 10; // alterarmos A[1][1] de 2 para 10
we replicate the changes to all rows.
I would like you to tell me about this JavaScript behavior:
- The problems that careless use can entail, and
- What is the simplest and most acceptable way to create this array and make these changes to it.
Answer:
If you want to independently change the values, you need something like this:
var linha = [1, 2, 3, 4, 5]; var matriz = []; for( var i = 0; i<5; i++ ) { matriz.push( linha.slice() ); } //testando alteração: matriz[2][2] = 999; for( var i = 0; i<5; i++ ) { body_log( 'matriz[' + i + ']:' + matriz[i] ); } // só pra nao precisar de console: function body_log(msg) { document.body.innerHTML = document.body.innerHTML + '<p>' + msg + '</p>'; }
What's happening here is that .slice()
is one of the ways to produce a clone of an array , not a new reference.
As you mentioned yourself, when someone does umaVariavel = umArray
in JS, they are simply saying that umaVariavel
points to the same memory space as umArray
, and the consequence is that when you access either of the two things, you are seeing the same data. Any changes made, whether by one name or another, will be reflected when accessing them.
The same thing happens when you point an array sub-index to another array. That sub-index will be pointing to the same space as the original variable.
Recursion behavior
The following example is to confuse some and worry others. Try to understand what happens when you, in addition to using arrays by reference, make the reference within the array itself:
var matriz = []; matriz.push( [00, 01, 02, 03, 04, 05] ); matriz.push( [10, 11, 12, 13, 14, 15] ); matriz.push( [20, 21, 22, 23, 24, 25] ); matriz.push( [30, 31, 32, matriz, 34, 35] ); matriz.push( [40, 41, 42, 43, 44, 45] ); matriz.push( [50, 51, 52, 53, 54, 55] ); body_log( 'matriz[1][1] <br>' + matriz[1][1] ); body_log( 'matriz[2][2] <br>' + matriz[2][2] ); body_log( 'matriz[3][3] <br>' + matriz[3][3] ); body_log( 'matriz[3][3][2] <br>' + matriz[3][3][2] ); body_log( 'matriz[3][3][1][2]<br>' + matriz[3][3][1][2] ); // alterando: matriz[3][3][1][2] = 999; body_log( 'matriz[3][3][1][2] = 999<br>'); body_log( 'resultado:<br>' + matriz ); matriz[0][0] = matriz[3]; matriz[3][3][0][0][3][4] = "que?"; body_log( 'matriz[0][0] = matriz[3] e matriz[3][3][0][0][3][4] = "que?"' ); body_log( 'resultado:<br>' + matriz ); function body_log(msg) { document.body.innerHTML = document.body.innerHTML + '<p>' + msg + '</p>'; }
See how the array can access itself through one of its members? I hope you're seeing this example in a well-implemented browser that simply hides member 3,3 of the array , otherwise it will collapse.
Note that when we change member [3][3][1][2] of the array we are actually changing member [1][2], because member [3][3] is the array itself.
To make matters worse, I added a change to the demo by transforming the item [0][0] in row 3 of the matrix, and changing one of its members, and changing the entire row 4 to a string, through three recursions. For those who like to play Portal , it's easy to understand.
Imagine in a real case the kind of confusion you can make when you don't know the difference between a true value and a mere reference.