Fix in Javascript of different objects returns the same object when accessing all its elements

2

I have a problem manipulating an arrangement in Javascript that I could not solve or explain the behavior.

Initially I have 9 buttons inside a div numbered from 1 to 9. By clicking on the button 5 the numbers of the buttons around it must turn in the sense of the needles of the clock.

To do this I add an event (I can not use jQuery) by directly manipulating the DOM. I create an array and I add the 8 buttons in the respective order, clone the array, to the cloned array I remove the last element and add it to the beginning (so I simulate moving the elements in a clockwise direction), then I assign the value of the objects of the cloned array to the new array.

The inconvenience that occurs is that you are assigning the number 4 to all the values surrounding the number 5. To verify this, in the code I added two codes that, first, show me the permuted cloned array and the values are the appropriate, but in the second for cycle, when returning to show the values of the permuted array are exactly the same (the number 4) without altering the array.

What could be happening?

var button5 = document.getElementById("btn5");
button5.onclick = function() {
  var arrButtons = [];
  
  //Inicialmente el arreglo contendrá los objetos a
  //los botones representados por 1,2,3,6,9,8,7,4
  arrButtons.push(document.getElementById("btn1"));
  arrButtons.push(document.getElementById("btn2"));
  arrButtons.push(document.getElementById("btn3"));
  arrButtons.push(document.getElementById("btn6"));
  arrButtons.push(document.getElementById("btn9"));
  arrButtons.push(document.getElementById("btn8"));
  arrButtons.push(document.getElementById("btn7"));
  arrButtons.push(document.getElementById("btn4"));
  
  //Clono el arreglo inicial.
  var newButtons = arrButtons.slice();
  
  //Permutar en el sentido de las agujas del reloj.
  newButtons.unshift(newButtons.pop());
  
  //Muestra el arreglo permutado correctamente
  //De 1,2,3,6,9,8,7,4 ahora es 4,1,2,3,6,9,8,7 en la primera iteración
  for (var i = 0; i < arrButtons.length; i++) {
    console.log(newButtons[i].innerHTML);
  }
  for (var i = 0; i < arrButtons.length; i++) {
    //Pero ahora solo muestra 4 para cada valor de newButtons[i] en la primera iteración
    console.log(newButtons[i].innerHTML)
    arrButtons[i].innerHTML = newButtons[i].innerHTML;
  }
}
#btns {
  width: 75%
}
#btns .btn {
  width: 30%;
  height: 48px;
  font-size: 24px;
}
<div id="btns">
  <button id="btn1" class="btn">1</button>
  <button id="btn2" class="btn">2</button>
  <button id="btn3" class="btn">3</button>
  <button id="btn4" class="btn">4</button>
  <button id="btn5" class="btn">5</button>
  <button id="btn6" class="btn">6</button>
  <button id="btn7" class="btn">7</button>
  <button id="btn8" class="btn">8</button>
  <button id="btn9" class="btn">9</button>
</div>
    
asked by dwarandae 06.03.2016 в 04:25
source

2 answers

0

The problem is the order of the last loop. When you read the value of an item it has already been updated in the previous step and it does not have the value that you think it has (the old one) but a different one (the new one that is 4).

Let's see it step by step:

  • Assign the value of the first element (4) to the second element (1)
  • Assign the value of the second element (now 4) to the third element (2)
  • Assign the value of the third element (now 4) to the fourth element (3)
  • Assign the value of the fourth element (now 4) to the fifth element (6)
  • ...
  • And so with all the elements of the array. This happens like this because although they are two different arrays, the elements are the same in both arrays (you could see them as references to the same element). So modifying the innerHTML of an element in an array, you are changing the innerHTML of the same element in the other array (which is in another position)

    One possible solution would be to traverse the array in the opposite direction. In this way you do not encounter this problem (although you would still have a problem with the first / last element, so you would need to save it in a variable and assign it to the end, as you need an additional variable when you want to exchange values between two variables).

    var button5 = document.getElementById("btn5");
    button5.onclick = function() {
      var arrButtons = [];
      //Inicialmente el arreglo contendrá los objetos a
      //los botones representados por 1,2,3,6,9,8,7,4
      arrButtons.push(document.getElementById("btn1"));
      arrButtons.push(document.getElementById("btn2"));
      arrButtons.push(document.getElementById("btn3"));
      arrButtons.push(document.getElementById("btn6"));
      arrButtons.push(document.getElementById("btn9"));
      arrButtons.push(document.getElementById("btn8"));
      arrButtons.push(document.getElementById("btn7"));
      arrButtons.push(document.getElementById("btn4"));
      //Clono el arreglo inicial.
      var newButtons = arrButtons.slice();
      //Permutar en el sentido de las agujas del reloj.
      newButtons.unshift(newButtons.pop());
    
      // guarda el valor del último valor en una variable auxiliar
      var original = arrButtons[arrButtons.length -1 ].innerHTML;
      // recorre el array en sentido inverso para evitar que todos tengan el mismo valor
      for (var i = arrButtons.length-1; i >= 0; i--) {
        console.log(arrButtons[i].innerHTML + " = " + newButtons[i].innerHTML);
        arrButtons[i].innerHTML = newButtons[i].innerHTML;
      }
      // asigna la variable auxiliar al primer elemento
      arrButtons[0].innerHTML = original;
    }
    #btns {
      width: 75%
    }
    #btns .btn {
      width: 30%;
      height: 48px;
      font-size: 24px;
    }
    <div id="btns">
      <button id="btn1" class="btn">1</button>
      <button id="btn2" class="btn">2</button>
      <button id="btn3" class="btn">3</button>
      <button id="btn4" class="btn">4</button>
      <button id="btn5" class="btn">5</button>
      <button id="btn6" class="btn">6</button>
      <button id="btn7" class="btn">7</button>
      <button id="btn8" class="btn">8</button>
      <button id="btn9" class="btn">9</button>
    </div>
        
    answered by 06.03.2016 / 04:51
    source
    1

    As I explained to you @AlvaroMontoro here , you have a problem with the order in which you process the elements, to its explanation I will add that the root of the problem is that slice makes a superficial copy of the arrangement and therefore both arrays have the same elements, but in a different order.

    That explains why they are overwritten and why processing them in the reverse order works (with the patch of the first / last element).

    Now, to avoid the problem of the first or the last element, I propose this alternative approach, which consists in storing the content of the buttons in a separate arrangement according to a pre-established order, then "rotating" the order of processing and finally re-set the values in the elements according to the new order.

    var button5 = document.getElementById("btn5")
    button5.onclick = function() {
      var order = [1, 2, 3, 6, 9, 8, 7, 4]
          content = []
    
      order.forEach(function(ix) {
        content.push(document.getElementById("btn" + ix).innerHTML)
      })
    
      // sentido horario - cambiando solo el orden de procesamiento
      order.push(order.shift())
    
      // sentido anti-horario
      //order.unshift(order.pop())
    
      order.forEach(function(ix) {
        document.getElementById("btn" + ix).innerHTML = content.shift()
      })
    }
    #btns {
      width: 75%
    }
    #btns .btn {
      width: 30%;
      height: 48px;
      font-size: 24px;
    }
    <div id="btns">
      <button id="btn1" class="btn">1</button>
      <button id="btn2" class="btn">2</button>
      <button id="btn3" class="btn">3</button>
      <button id="btn4" class="btn">4</button>
      <button id="btn5" class="btn">5</button>
      <button id="btn6" class="btn">6</button>
      <button id="btn7" class="btn">7</button>
      <button id="btn8" class="btn">8</button>
      <button id="btn9" class="btn">9</button>
    </div>
        
    answered by 06.03.2016 в 05:24