Как очистить выбранные элементы из списка - PullRequest
0 голосов
/ 24 января 2020

У меня проблемы с работой этой функции. Вместо удаления всех элементов списка TODO, который я выбрал, он удаляет половину из них. Если у меня есть список с 1 2 3 4 5 6 7 8, он удаляет 1 3 5 7.

clearCompleted: function() {
       var clearCompleted = document.getElementById("clearCompleted");
       clearCompleted.addEventListener("click", function() {
         for (var i = 0; i < todoList.todos.length; i++) {
           todoList.todos[i]
           if (todoList.todos[i].completed === true) {
             todoList.deleteTodo(i);
            }
           }
              view.displayTodos()
         })
     }

   deleteTodo: function (position){
      this.todos.splice(position,1);
    },

Ответы [ 2 ]

2 голосов
/ 24 января 2020

let todos = [
  {"id": 0, "completed":  true, "name": "done :)"},
  {"id": 1, "completed":  true, "name": "done-skippedThisIndex :("},
  {"id": 2, "completed": false, "name": "working on it"}, 
  {"id": 3, "completed": false, "name": "incomplete"}, 
  {"id": 4, "completed":  true, "name": "finished"},  
  {"id": 5, "completed":  true, "name": "complete-skippedThisIndex :("},
  {"id": 6, "completed":  true, "name": "complete-neverSeesThisIndex :)"},  
  {"id": 7, "completed":  true, "name": "complete-lengthWasShortened :("}
];
//console.log("BEFORE:(length:", todos.length, ")\n", todos);

todos = todos.filter(function(todo, i){
  console.log(i, "of", todos.length, todo);
  return (todo.completed === false);
});

console.log("AFTER:(length:", todos.length, ")\n", todos);

Примечание: я только передал i, поэтому console.log мог показать, что все элементы массива были обработаны для сравнения с кодом в следующем примере, что эквивалентно к вашему коду.
На самом деле вам нужен только следующий код:

todos = todos.filter(function(todo){
  return (todo.completed === false);
});

С синтаксисом ES6 это может быть сокращено еще больше:

todos = todos.filter(todo => todo.completed === false);

Вот эквивалент вашего кода. Если вы изучите вывод console.log, то увидите, что при удалении элементов из массива i больше не соответствует номеру id. Это связано с тем, что по мере продвижения элемента в массиве значение, на которое указывает i, изменяется. В результате то, что было бы следующим элементом, на который смотрел ваш массив, теперь занимает пространственное местоположение текущего i. Теперь при следующем проходе l oop, i приращения и элемент, который двигался вперед, таким образом, никогда не просматривается. Это приводит к тому, что некоторые элементы «пропускаются».

let todos = [
  {"id": 0, "completed":  true, "name": "done :)"},
  {"id": 1, "completed":  true, "name": "done-skippedThisIndex :("},
  {"id": 2, "completed": false, "name": "working on it"}, 
  {"id": 3, "completed": false, "name": "incomplete"}, 
  {"id": 4, "completed":  true, "name": "finished"},  
  {"id": 5, "completed":  true, "name": "complete-skippedThisIndex :("},
  {"id": 6, "completed":  true, "name": "complete-neverSeesThisIndex :)"},  
  {"id": 7, "completed":  true, "name": "complete-lengthWasShortened :("}
];
//console.log("BEFORE:(length:", todos.length, ")\n", todos);

for (var i = 0; i < todos.length; i++) {
  if (todos[i].completed === true) {
    console.log(i,"of", todos.length, ": REMOVING", todos[i]);
    todos.splice(i, 1);
    console.log("    ", todos.length, "(new  length - next id will be skipped over)\n");
  } else {
    console.log(i,"of", todos.length, ": keeping", todos[i]);
    console.log("    ", todos.length, "(same length)\n");
  }
}

console.log("AFTER:(length:", todos.length, ")\n", todos);

Чтобы сохранить созданную вами циклическую конструкцию, просто измените свой код, чтобы не изменять массив во время его цикла. Вы можете создать новый массив, который вы будете заполнять элементами, которые хотите сохранить. Затем переназначьте новый массив старой переменной:

let todos = [
  {"id": 0, "completed":  true, "name": "done :)"},
  {"id": 1, "completed":  true, "name": "done-skippedThisIndex :("},
  {"id": 2, "completed": false, "name": "working on it"}, 
  {"id": 3, "completed": false, "name": "incomplete"}, 
  {"id": 4, "completed":  true, "name": "finished"},  
  {"id": 5, "completed":  true, "name": "complete-skippedThisIndex :("},
  {"id": 6, "completed":  true, "name": "complete-neverSeesThisIndex :)"},  
  {"id": 7, "completed":  true, "name": "complete-lengthWasShortened :("}
];
//console.log("BEFORE:(length:", todos.length, ")\n", todos);

newTodos = [];
for (var i = 0; i < todos.length; i++) {
  if (todos[i].completed === false) {
    console.log(i,"of", todos.length, ": keeping", todos[i]);
    newTodos.push(todos[i]);
  }
  else {
    console.log(i,"of", todos.length, ": NOT keeping", todos[i]); 
  }
}
todos = newTodos;
console.log("AFTER:(length:", todos.length, ")\n", todos);

Здесь вы можете видеть, что все элементы фактически просматриваются, индекс не пропускается.
В результате получаются именно те элементы, которые вам нужны.

Другой «хакерский», НЕ рекомендуемый способ, который вы могли бы использовать, - противодействовать эффекту изменения индекса следующего элемента путем уменьшения текущего индекса, когда вы splice выводите текущий элемент. Таким образом, в начале l oop вы должны увеличить i, чтобы он указывал на следующий элемент, на который вы хотите посмотреть:

let todos = [
  {"id": 0, "completed":  true, "name": "done :)"},
  {"id": 1, "completed":  true, "name": "done-skippedThisIndex :("},
  {"id": 2, "completed": false, "name": "working on it"}, 
  {"id": 3, "completed": false, "name": "incomplete"}, 
  {"id": 4, "completed":  true, "name": "finished"},  
  {"id": 5, "completed":  true, "name": "complete-skippedThisIndex :("},
  {"id": 6, "completed":  true, "name": "complete-neverSeesThisIndex :)"},  
  {"id": 7, "completed":  true, "name": "complete-lengthWasShortened :("}
];
//console.log("BEFORE:(length:", todos.length, ")\n", todos);

for (var i = 0; i < todos.length; i++) {
  if (todos[i].completed === true) {
    console.log(i,"of", todos.length, ": REMOVING", todos[i]);
    todos.splice(i, 1);
    i--;  // decrement i to reflect that the data moved backwards in the array
    console.log("    ", todos.length, "(new length)\n    ", i, "(new i)  decremented i to reflect that the data moved backwards/(to the left by 1) in the array. \n     Now, all items will still be looked at)\n");
  } else {
    console.log(i,"of", todos.length, ": keeping", todos[i]);
    console.log("    ", todos.length, "(same length)\n");
  }
}

console.log("AFTER:(length:", todos.length, ")\n", todos);

Это достигается путем добавления i-- сразу после выполнения splice(i, 1), чтобы отразить, что оставшиеся данные теперь расположены ровно на 1 позицию слева от того места, где они были ранее. , Это гарантирует, что все данные будут просмотрены и оценены. Это не рекомендуемый способ справиться с этой ситуацией, но может пригодиться в других сложных ситуациях.

for (var i = 0; i < todos.length; i++) {
  if (todos[i].completed === true) {
    todos.splice(i, 1);
    i--;   // all the data moved left, update the index accordingly
  }
}
1 голос
/ 24 января 2020

Таким образом, проблема будет заключаться в следующем: вы изменяете массив списка задач при выполнении команды для l oop. Я приведу здесь небольшой пример:

const arr = [1, 2, 3, 4]
for (var i = 0; i < arr.length; i++) {
  console.log('i', i)
  arr.splice(i, 1)
}

console.log(arr) // [2, 4]

Если вы запустите этот пример, конечный результат arr будет [2, 4]:

  • , выполняющим первую итерацию когда i = 0 вы удалили первый элемент arr, то есть 1, теперь arr становится [2, 3, 4]
  • , выполняя вторую итерацию, когда i = 1, вы удалили второй элемент arr, так как теперь arr изменены, он больше не [1, 2, 3, 4], его [2, 3, 4], второй элемент 3, поэтому arr становится [2, 4]
  • , выполняющим третью итерацию , когда i = 2, сейчас arr.length = i, l oop заканчивается

Так как решить эту проблему:

Я бы сказал, сохранить массив неизменный , не используйте splice(), используйте slice(). Или я рекомендую использовать filter / map / reduce эти "функции высокого порядка API". Эти API не изменят исходный массив, а вместо этого вернут новый массив. Вот статья об использовании «неизменяемого шаблона»

Не уверен, решит ли это вашу проблему. Надежда помогает.

...