「for .. of」ループを使用して、Vanilla JavaScriptのSelectタグからオプションを削除する


10

選択からオプションを削除しようとすると、常に1つ残っていますが、なぜですか?

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

このJSは機能していません:

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

そして、これも機能していません:

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

それを達成するための他の解決策があることを知っていますが、なぜそれが想定どおりに機能しないのかを理解したいと思います

回答:


7

.optionsコレクションは、(残念ながら)でライブ一つずつライブコレクションの項目を反復処理し、よう、.remove一人一人が保管されているすべての奇数1になりますINGの。(例えば、あなたが最初の項目を削除すると、右、[0]コレクションの番目の項目はすぐになります次のコレクション内の項目-にするために使用するもの[1]になるだろう[0](そしてあなたがで次のインデックスに進みたら[1]新しい位置にあるアイテム0は繰り返されません)

使用するdocument.querySelectorAll静的なコレクションを返す、代わりに:

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>

要素を削除する前に、(静的)配列に展開することもできます。

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>

コレクションがライブであるためにたまたま機能する別のオプション(ただし、直感的でないため、おそらく使用しないでください):

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>


3

配列を反復処理するときに、配列から項目を削除しています。だからあなたは持っています:

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

次に、インデックス0のアイテムを削除します。これは「1」であり、次のようになります。

["two","three"]

次に、インデックス3のアイテムを削除します。

["two"]

インデックス2にはアイテムがないため、ループは停止します。

代わりに、配列をに反復します。

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>


.optionsはない問題の発生源である配列、 -むしろ、それは生きているHTMLCollection、です。それが配列だったら、それは静的で、問題はありません。
特定のパフォーマンス

1
@CertainPerformance反復処理中に配列から要素を削除すると、私が説明した問題発生します。
シンボリックリンク

1
@CertainPerformance HTMLOptionsCollectionオブジェクトは、このコンテキストでは配列のように機能します。
シンボリックリンク

2

あなたの主な目標は、これが発生する原因となるプロセスを理解することであるため、これが問題を示しているはずです。

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) + ".");

このループは、「for .. of」ループが通過するのとまったく同じタイプのプロセスを通過して、最終結果に余分なものを残します。問題は、それが反復しているときに自身のインデックスを破壊し、i実際に参照している値を変更することです。この問題に直面しているときは、配列を逆方向にループして、自分の破壊の影響を受けないようにします。

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) + ".");

これがここで何が起こっているのかを完全に理解するのに役立つことを願っています。質問がある場合は、コメントを残してください。


0

配列から項目を削除すると、インデックスが変更される同じ配列をループします。以下は、インデックスなしでオプションをループして配列から削除できるサンプルです。

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

ここがフィドルです

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.