Czy w prostym javascript (tj. Bez rozszerzeń takich jak jQuery itp.) Istnieje sposób na określenie indeksu węzła podrzędnego w jego węźle nadrzędnym bez iteracji i porównywania wszystkich węzłów potomnych?
Na przykład,
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;
}
}
Czy istnieje lepszy sposób określenia indeksu dziecka?
javascript
dom
Wszyscy pracownicy są niezbędni
źródło
źródło
parent.childNodes
, a nieparent.children
?. Ta ostatnia wymienia tylkoElements
, wyłączając poszczególneText
węzły ... Część odpowiedzi, np. UżywaniepreviousSibling
, opiera się na wykorzystaniu wszystkich węzłów potomnych, podczas gdy inne dotyczą tylko dzieci, które sąElement
... (!).childNodes
zdecydowanie powinien być używany zamiast.children
. Jak wskazałeś, 2 najczęściej opublikowane odpowiedzi dadzą różne wyniki.Odpowiedzi:
możesz użyć tej
previousSibling
właściwości, aby przejść wstecz przez rodzeństwo, aż wrócisznull
i policzyć, ile rodzeństwa spotkałeś:Należy pamiętać, że w językach takich jak Java istnieje
getPreviousSibling()
funkcja, jednak w JS stała się ona właściwością -previousSibling
.źródło
for (var i=0; (node=node.previousSibling); i++);
i
będzie dostępny..previousSibling
i.previousElementSibling
. Pierwsza trafia w węzły tekstowe, druga nie.Polubiłem
indexOf
do tego używać . PonieważindexOf
jest włączonyArray.prototype
iparent.children
jestNodeList
, musisz go użyć.call();
Jest trochę brzydki, ale ma jedną linijkę i wykorzystuje funkcje, które i tak powinien znać każdy programista javascript.źródło
[]
tworzy wystąpienie Array za każdym razem, gdy uruchamiasz ten kod, co jest mniej wydajne w przypadku pamięci i GC w porównaniu z użyciemArray.prototype
.[]
pamięć nie jest czyszczona jako wartość śmieci?[].indexOf
silnik musi utworzyć instancję tablicy, aby uzyskać dostęp doindexOf
implementacji w prototypie. Sama instancja pozostaje nieużywana (robi GC, to nie jest wyciek, to tylko marnowanie cykli).Array.prototype.indexOf
uzyskuje dostęp do tej implementacji bezpośrednio bez przydzielania anonimowej instancji. Różnica będzie znikoma w prawie wszystkich okolicznościach, więc szczerze mówiąc, może nie warto się tym przejmować.ES6:
Wyjaśnienie:
element.parentNode.children
→ Zwraca braci zelement
, w tym ten element.Array.from
→ Rzutuje konstruktorachildren
naArray
obiektindexOf
→ Możesz złożyć wniosek,indexOf
ponieważ masz terazArray
przedmiot.źródło
Array.from
prace nad Internet Explorercreates a new Array instance from an array-like or iterable object.
Utworzenie nowej instancji tablicy tylko w celu znalezienia indeksu może nie być wydajne dla pamięci lub GC, w zależności od częstotliwości operacji, w takim przypadku iteracja, jak wyjaśniono w zaakceptowanej odpowiedzi, byłaby większa ideał.ES - krótszy
Operator spreadu jest do tego skrótem
źródło
e.parentElement.childNodes
ie.parentNode.children
?childNodes
zawiera również węzły tekstoweType 'NodeListOf<ChildNode>' must have a '[Symbol.iterator]()' method that returns an iterator.ts(2488)
Dodawanie (z prefiksem dla bezpieczeństwa) element.getParentIndex ():
źródło
if (!Element.prototype.getParentIndex) Element.prototype.getParentIndex = function(){ /* code here */ }
? W każdym razie, jeśli kiedykolwiek zostanie to zaimplementowane w standardzie w przyszłości, prawdopodobnie zostanie zaimplementowane jako getterelement.parentIndex
. Więc powiedziałbym, że najlepszym podejściem byłobyif(!Element.prototype.getParentIndex) Element.prototype.getParentIndex=Element.prototype.parentIndex?function() {return this.parentIndex}:function() {return Array.prototype.indexOf.call(this.parentNode.children, this)}
getParentIndex()
może mieć inny podpis niż Twoja implementacja.𝗣𝗿𝗼𝗼𝗳 𝗢𝗳 𝗔 𝗟𝗲𝘀𝘀 𝗘𝗳𝗳𝗶𝗰𝗶𝗲𝗻𝘁 𝗕𝗶𝗻𝗮𝗿𝘆 𝗦𝗲𝗮𝗿𝗰𝗵
Stawiam hipotezę, że biorąc pod uwagę element, w którym wszystkie jego elementy podrzędne są uporządkowane w dokumencie po kolei, najszybszym sposobem powinno być przeszukanie binarne, porównując pozycje elementów w dokumencie. Jednak, jak wprowadzono we wniosku, hipoteza zostaje odrzucona. Im więcej masz elementów, tym większy potencjał wydajności. Na przykład, gdybyś miał 256 elementów, to (optymalnie) musiałbyś sprawdzić tylko 16 z nich! Dla 65536 tylko 256! Wydajność rośnie do potęgi 2! Zobacz więcej liczb / statystyk. Odwiedź Wikipedię
Następnie sposób, w jaki go używasz, polega na uzyskaniu właściwości „parentIndex” dowolnego elementu. Na przykład sprawdź następujące demo.
Ograniczenia
Wyszukiwanie binarne VS liniowe na 200 000 elementów (może spowodować awarię niektórych przeglądarek mobilnych, OSTROŻNIE!):
Wyszukiwanie binarne
Pokaż fragment kodu
Wyszukiwanie liniowe wstecz (`lastIndexOf`)
Pokaż fragment kodu
Wyszukiwanie liniowe do przodu (`indexOf`)
Pokaż fragment kodu
PoprzedniElementSibling Counter Search
Zlicza liczbę PreviousElementSiblings, aby uzyskać parentIndex.
Pokaż fragment kodu
Brak wyszukiwania
Do analizy porównawczej, jaki byłby wynik testu, gdyby przeglądarka zoptymalizowała wyszukiwanie.
Pokaż fragment kodu
The Conculsion
Jednak po przejrzeniu wyników w Chrome wyniki są odwrotne od oczekiwanych. Głupsze wyszukiwanie liniowe do przodu było zaskakujące o 187 ms, 3850%, szybciej niż wyszukiwanie binarne. Najwyraźniej Chrome w jakiś magiczny sposób przechytrzył
console.assert
i zoptymalizował go lub (bardziej optymistycznie) Chrome wewnętrznie używa numerycznego systemu indeksowania dla DOM, a ten wewnętrzny system indeksowania jest ujawniany poprzez optymalizacje zastosowaneArray.prototype.indexOf
naHTMLCollection
obiekcie.źródło
Użyj algorytmu wyszukiwania binarnego, aby poprawić wydajność, gdy węzeł ma dużo rodzeństwa.
źródło
Miałem problem z węzłami tekstowymi i pokazywał zły indeks. Oto wersja, aby to naprawić.
źródło
Dawny
źródło
Element.prototype
? Funkcje wyglądają na przydatne, ale nie wiem, do czego służą (nawet jeśli nazwy są oczywiste).el.group.value()
??. Mój pierwszy komentarz ma na celu poprawę jakości Twojej odpowiedzi.Czy mógłbyś zrobić coś takiego:
https://developer.mozilla.org/en-US/docs/Web/API/Node/parentElement
źródło
źródło