Странное поведение splice в цикле
При попытке удалить все элементы из массива методом splice через цикл получаю следующее:
const arr = [1, 2, 0, 3, 0, 0, 0, 3, 4, 5, 7];
for (let i = 0; i < arr.length; i++) {
arr.splice(i, 1);
console.log(arr, i)
}
console.log(arr); // [2, 3, 0, 3, 5]
Код удаляет каждый второй элемент, а по задумке должен оставить пустой массив.
Ещё пример:
const arr = [1, 2, 0, 3, 0, 0, 0, 3, 4, 5, 7];
for (const elem of arr) {
arr.splice(elem, 1);
console.log(arr, elem);
}
console.log(arr); // [0, 0, 0, 3, 5, 7]
Здесь результат просто странный. Как будто метод сам решил, что удалять, а что нет.
В чем ошибка?
Ответы (1 шт):
Главным образом ошибка в Вашей логике. По ней Вы и в первом и во втором случае обращаетесь к массиву как будто он не изменен, но это не так Вы же удаляете элементы
В первом случае удаляя каждый раз с нарастающим индексом Вы как-бы перескакиваете через элемент, так как при удалении индексы тоже уменьшились на 1, а i увеличилось на 1.
0,1,2,3,4,5 (начальное состояние)
^
1,2,3,4,5 (при удалении элемента индексы уменьшились на 1)
^
1,2,3,4,5 (i увеличилось на 1)
^
Во втором случае Вы первым элементом передаете уже не индекс а значение элемента - тут конечно все будет не так очевидно.
Таким образом выровнять ситуацию просто:
const arr = [1, 2, 0, 3, 0, 0, 0, 3, 4, 5, 7];
for (let i = 0; i < arr.length; i++) {
arr.splice(0, 1);
}
console.log(arr); // [0, 3, 4, 5, 7]
const arr = [1, 2, 0, 3, 0, 0, 0, 3, 4, 5, 7];
for (const elem of arr) {
arr.splice(0, 1);
}
console.log(arr); // [0, 3, 4, 5, 7]
Но это не очищает оба массива как предполагается, по причине того что массивы мутируют. А в случае for, for of и for in значения длины массива высчитывается не верно, заметьте, что 0, 3, 4, 5, 7 - это последние числа в массиве, до них дело просто не доходит, так как в условии i < arr.length и i, и arr.length движуться навстречу друг другу и останавливаются примерно на середине ,например при: 5 < 5
Но этого не происходит при while который каждый раз получает актуальную длину массива и условие выхода уже соответствует ожиданиям, т.е. while позволяет любые мутации интегрируемого объекта, но по возможности их стоит избегать.
const arr = [1, 2, 0, 3, 0, 0, 0, 3, 4, 5, 7];
while (arr.length) {
arr.splice(0, 1);
}
console.log(arr); // []