Цикл for обходит не всю коллекцию

Есть таблица, которая генерируется следующим образом:

let table = document.createElement("table");
table.setAttribute('border','1');

for (let i = 0; i < 5; i++) {
    let newRow = table.insertRow(0);
    for (let j = 0; j < 5; j++) {
        let newCell = newRow.insertCell(0);
        newCell.className = "white_cell";
    }
}

document.getElementById("for_table").appendChild(table)

Есть кнопка, которая должна менять цвет ячеек с белого на чёрный с помощью такой функции

function change_color() {
    let arrCell_w = document.getElementsByClassName("white_cell");
    console.log(arrCell_w.length);
    console.log(arrCell_w);
    for (let i = 0; i < arrCell_w.length; i++) {
       //console.log(i)
       //console.log(arrCell_w[i]);       
         arrCell_w[i].className = "black_cell";
    }
}

Судя по логам, находятся всё, что нужно, но цвет меняется только у половины ячеек. Подскажите, пожалуйста, в чём может быть ошибка?


Ответы (1 шт):

Автор решения: Alexander Lonberg

getElementsByClassName возвращает "живую" HTMLCollection коллекцию элементов.

На первой итерации мы получаем первый элемент по индексу [0] и изменяем его класс cell.black_cell. В этот момент коллекция table.cell.white_cell обновляется и первый элемент из нее выпадает. На второй итерации мы обращаемся к индексу [1], но в обновленной коллекции, второй элемент таблицы сместился в индекс [0]. Таким образом, мы пропустили второй элемент и реально получили третий. По итогу раскрасится все через один элемент.

index table 1 итерация / index cell 2 итерация / index cell
0 c_white [0] <- мы тут c_black
1 c_white [1] c_white [0] <- пропустили
2 c_white [2] c_white [1] <- мы тут

Просто превратим эту коллекцию в "неживой" массив.

let table = document.createElement("table")
table.setAttribute('border', '1')

for (let i = 0; i < 5; i++) {
  let newRow = table.insertRow(0)
  for (let j = 0; j < 5; j++) {
    let newCell = newRow.insertCell(0)
    newCell.className = "white_cell"
    newCell.textContent = "Cell"
  }
}

document.body.appendChild(table)

function change_color() {
  let arrCell_w = [...document.getElementsByClassName("white_cell")]
  for (let i = 0; i < arrCell_w.length; i++) {
    arrCell_w[i].className = "black_cell"
  }
}

document.querySelector("button").addEventListener("click", change_color)
.white_cell {
  background-color: white;
}

.black_cell {
  background-color: darkgray;
}
<button start>Start</button>

→ Ссылка