Dalam javascript lurus (yaitu, tidak ada ekstensi seperti jQuery, dll.), Apakah ada cara untuk menentukan indeks simpul anak di dalam simpul induknya tanpa mengulang dan membandingkan semua simpul anak?
Misalnya,
var child = document.getElementById('my_element');
var parent = child.parentNode;
var childNodes = parent.childNodes;
var count = childNodes.length;
var child_index;
for (var i = 0; i < count; ++i) {
if (child === childNodes[i]) {
child_index = i;
break;
}
}
Apakah ada cara yang lebih baik untuk menentukan indeks anak?
javascript
dom
Semua Pekerja Sangat Penting
sumber
sumber
parent.childNodes
, bukanparent.children
?. Yang terakhir hanya mencantumkanElements
, tidak termasuk diText
simpul tertentu ... Beberapa jawaban di sini, misalnya menggunakanpreviousSibling
, didasarkan pada penggunaan semua simpul anak, sedangkan yang lain hanya terganggu dengan anak-anak yangElement
s ... (!).childNodes
pasti harus digunakan sebagai pengganti.children
. 2 jawaban teratas yang diposting akan memberikan hasil yang berbeda seperti yang Anda tunjukkan.Jawaban:
Anda bisa menggunakan
previousSibling
properti untuk mengulang kembali saudara kandung sampai Anda kembalinull
dan menghitung berapa banyak saudara yang Anda temui:Harap dicatat bahwa dalam bahasa seperti Java, ada
getPreviousSibling()
fungsi, namun di JS ini telah menjadi properti -previousSibling
.sumber
for (var i=0; (node=node.previousSibling); i++);
i
akan dapat diakses..previousSibling
dan.previousElementSibling
. Yang pertama mengenai node teks, yang terakhir tidak.Saya menjadi suka menggunakan
indexOf
untuk ini. KarenaindexOf
aktifArray.prototype
danparent.children
merupakanNodeList
, Anda harus menggunakancall();
Ini agak jelek tetapi ini adalah satu liner dan menggunakan fungsi yang harus dipahami oleh setiap pengembang javascript.sumber
[]
membuat instance Array setiap kali Anda menjalankan kode itu, yang kurang efisien untuk memori dan GC vs penggunaanArray.prototype
.[]
membersihkan memori sebagai nilai sampah?[].indexOf
mesin harus membuat turunan array hanya untuk mengaksesindexOf
implementasi pada prototipe. Instance itu sendiri tidak digunakan (melakukan GC, ini bukan kebocoran, ini hanya membuang-buang siklus).Array.prototype.indexOf
mengakses implementasi itu secara langsung tanpa mengalokasikan instance anonim. Perbedaan tersebut akan dapat diabaikan di hampir semua keadaan, jadi terus terang mungkin tidak ada gunanya untuk diperhatikan.ES6:
Penjelasan:
element.parentNode.children
→ Menampilkan saudara darielement
, termasuk elemen itu.Array.from
→ Melemparkan konstruktor darichildren
sebuahArray
objekindexOf
→ Anda dapat melamarindexOf
karena sekarang Anda memilikiArray
objek.sumber
Array.from
karya di Internet explorercreates a new Array instance from an array-like or iterable object.
Membuat instance array baru hanya untuk menemukan indeks mungkin bukan memori atau GC yang efisien, bergantung pada seberapa sering operasi, dalam hal ini iterasi, seperti yang dijelaskan dalam jawaban yang diterima, akan lebih banyak ideal.ES — Lebih pendek
Operator penyebaran adalah jalan pintas untuk itu
sumber
e.parentElement.childNodes
dane.parentNode.children
?childNodes
menyertakan node teks jugaType 'NodeListOf<ChildNode>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
Menambahkan elemen (diawali untuk keselamatan ).getParentIndex ():
sumber
if (!Element.prototype.getParentIndex) Element.prototype.getParentIndex = function(){ /* code here */ }
? Bagaimanapun, jika ini pernah diimplementasikan menjadi standar di masa depan maka kemungkinan akan diterapkan sebagai getter likeelement.parentIndex
. Jadi, menurut saya pendekatan terbaik adalahif(!Element.prototype.getParentIndex) Element.prototype.getParentIndex=Element.prototype.parentIndex?function() {return this.parentIndex}:function() {return Array.prototype.indexOf.call(this.parentNode.children, this)}
getParentIndex()
mungkin memiliki tanda tangan yang berbeda dari implementasi Anda.Saya berhipotesis bahwa dengan adanya elemen di mana semua anaknya diurutkan pada dokumen secara berurutan, cara tercepat adalah melakukan pencarian biner, membandingkan posisi dokumen dari elemen tersebut. Namun, seperti yang diperkenalkan dalam kesimpulan, hipotesis ditolak. Semakin banyak elemen yang Anda miliki, semakin besar potensi kinerja. Misalnya, jika Anda memiliki 256 elemen, maka (secara optimal) Anda hanya perlu memeriksa 16 elemen saja! Untuk 65536, hanya 256! Performa berkembang menjadi kekuatan 2! Lihat lebih banyak angka / statistik. Kunjungi Wikipedia
Lalu, cara Anda menggunakannya adalah dengan mendapatkan properti 'parentIndex' dari elemen apa pun. Misalnya, lihat demo berikut.
Batasan
Pencarian Biner VS Linear Pada 200 ribu elemen (mungkin merusak beberapa browser seluler, WASPADALAH!):
Pencarian Biner
Tampilkan cuplikan kode
Pencarian Linear Mundur (`lastIndexOf`)
Tampilkan cuplikan kode
Meneruskan (`indexOf`) Linear Search
Tampilkan cuplikan kode
Pencarian Konter PreviousElementSibling
Menghitung jumlah PreviousElementSiblings untuk mendapatkan parentIndex.
Tampilkan cuplikan kode
Tidak Ada Pencarian
Untuk pembandingan apa hasil dari pengujian jika browser mengoptimalkan pencarian.
Tampilkan cuplikan kode
Conculsion
Namun, setelah melihat hasilnya di Chrome, hasilnya berlawanan dengan yang diharapkan. Pencarian linier ke depan yang lebih bodoh ternyata 187 ms, 3850%, lebih cepat daripada pencarian biner. Terbukti, Chrome entah bagaimana secara ajaib mengakali
console.assert
dan mengoptimalkannya, atau (lebih optimis) Chrome secara internal menggunakan sistem pengindeksan numerik untuk DOM, dan sistem pengindeksan internal ini diekspos melalui pengoptimalan yang diterapkanArray.prototype.indexOf
saat digunakan padaHTMLCollection
objek.sumber
Gunakan algoritme penelusuran biner untuk meningkatkan performa saat node memiliki saudara dalam jumlah besar.
sumber
Saya memiliki masalah dengan node teks, dan itu menunjukkan indeks yang salah. Ini versi untuk memperbaikinya.
sumber
Ex
sumber
Element.prototype
? Fungsi terlihat berguna tapi saya tidak tahu apa fungsi fungsi ini (bahkan jika penamaannya jelas).el.group.value()
??. Komentar pertama saya ada untuk meningkatkan kualitas jawaban Anda.Bisakah Anda melakukan sesuatu seperti ini:
https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement
sumber
sumber