Menghapus opsi dari tag Pilih dalam JavaScript Vanilla dengan loop "for .. of"

10

Ketika mencoba untuk menghapus opsi dari pilih, selalu ada satu yang tersisa, mengapa?

<select id="form-select">   
<option>111</option>
<option>222</option>
<option>333</option>
</select>

JS ini tidak berfungsi:

var t = document.querySelector('#form-select'); 
for(var i of t.options) {
      t.remove(i.index)
    }

Dan ini juga tidak berfungsi:

for(var i of document.querySelector('#form-select').options) {
  i.remove()
}

Saya tahu bahwa ada solusi lain untuk mencapai itu, tetapi saya ingin memahami mengapa itu tidak berfungsi sebagaimana mestinya

Piotr
sumber

Jawaban:

7

The .optionsKoleksi ini (sayangnya) hidup , sehingga iterasi item live collection satu-per-satu dan .removeing setiap orang akan menghasilkan setiap aneh yang terus. (Misalnya, tepat ketika Anda menghapus item pertama, item [0]th koleksi akan segera menjadi item berikutnya dalam koleksi - apa yang [1]akan menjadi akan menjadi [0](dan kemudian setelah Anda pergi ke indeks berikutnya di [1], item baru di posisi 0 tidak akan diulangi lagi)

Gunakan document.querySelectorAllsebaliknya, yang mengembalikan koleksi yang statis:

for (const option of document.querySelectorAll('#form-select > option')) {
  option.remove();
}
<select id="form-select">
  <option>111</option>
  <option>222</option>
  <option>333</option>
</select>

Anda juga dapat menyebar ke array (statis) sebelum menghapus elemen ::

for (const option of [...document.querySelector('#form-select').options]) {
  option.remove();
}
<select id="form-select">
  <option>111</option>
  <option>222</option>
  <option>333</option>
</select>

Opsi lain yang kebetulan bekerja karena koleksinya adalah langsung (tetapi mungkin tidak boleh digunakan, karena tidak intuitif):

const { options } = document.querySelector('#form-select');
while (options.length) {
  options[0].remove();
}
<select id="form-select">
  <option>111</option>
  <option>222</option>
  <option>333</option>
</select>

Performa Tertentu
sumber
3

Anda menghapus item dari array, saat Anda beralih melalui array. Jadi kamu punya:

["one","two","three"]

maka Anda menghapus item di indeks 0, yang merupakan "satu," meninggalkan Anda dengan:

["two","three"]

selanjutnya Anda menghapus item di indeks 1, yaitu "tiga," meninggalkan Anda dengan:

["two"]

tidak ada item di indeks 2, jadi loop berhenti.

Iterate melalui array secara terbalik sebagai gantinya:

const t = document.querySelector("#form-select")

for (let i = t.options.length-1; i >= 0; i--) {
  t.removeChild(t.options[i])
}
<select id="form-select">
  <option>111</option>
  <option>222</option>
  <option>333</option>
</select>

symlink
sumber
The .optionsadalah tidak array, yang merupakan sumber masalah - bukan, ini merupakan HTMLCollection, yang hidup. Apakah itu array, itu akan menjadi statis, dan tidak akan ada masalah.
Kinerja Tertentu
1
@CertainPerformance menghapus elemen dari array seperti yang Anda iterate melalui itu tidak menyebabkan masalah saya sudah digambarkan.
symlink
1
@CertainPerformance Suatu HTMLOptionsCollectionobjek bertindak dalam konteks ini seperti sebuah array.
symlink
2

Saya melihat bahwa tujuan utama Anda adalah untuk memahami proses yang menyebabkan ini terjadi, jadi ini harus menggambarkan masalah bagi Anda:

var arr = ["one", "two", "three", "four", "five", "six"];

for(var i = 0; i < arr.length; i++){
	console.log("i is " + i + ", so we are removing \"" + arr[i] + "\" from " + JSON.stringify(arr) + ".");
	arr.splice(i, 1);
	console.log("After that removal, the array is " + JSON.stringify(arr) + ". We'll now iterate i to " + (i + 1) + " and continue the loop.");
}
console.log("i is too high to grab a value from the array, so we're finished. We're left with " + JSON.stringify(arr) + ".");

Loop ini melewati jenis proses yang sama persis dengan loop "for .. of" Anda untuk memberi Anda tambahan dalam hasil akhir. Masalahnya adalah bahwa ia menghancurkan indeks sendiri karena iterasi melalui mereka, sehingga mengubah nilai yang ibenar-benar merujuk. Ketika saya sedang menghadapi masalah ini, saya seperti loop melalui array mundur jadi saya tidak terpengaruh oleh kerusakan saya sendiri, seperti:

var arr = ["one", "two", "three", "four", "five", "six"];

for(var i = arr.length - 1; i >= 0; i--){
	console.log("i is " + i + ", so we are removing \"" + arr[i] + "\" from " + JSON.stringify(arr) + ".");
	arr.splice(i, 1);
	console.log("After that removal, the array is " + JSON.stringify(arr) + ". We'll now iterate i to " + (i - 1) + " and continue the loop.");
}
console.log("i is too low to grab a value from the array, so we're finished. We're left with " + JSON.stringify(arr) + ".");

Saya harap ini membantu Anda memahami apa yang terjadi di sini secara menyeluruh. Jika Anda memiliki pertanyaan, silakan beri saya komentar.

Aaron Plocharczyk
sumber
0

Anda mengulang melalui array yang sama di mana indeks berubah setelah Anda menghapus item dari array. Di bawah ini adalah contoh di mana Anda dapat mengulang melalui opsi tanpa indeks dan menghapusnya dari array.

var selectOptions = document.querySelectorAll('#remove-option>option');
selectOptions.forEach(function(selectOption) {
  selectOption.remove();
  selectOption = null;
});

Ini biola

kichus14
sumber