Как преобразовать список узлов DOM в массив в Javascript?
у меня есть функция Javascript, которая принимает список узлов HTML, но она ожидает массив Javascript (он запускает некоторые методы массива на этом), и я хочу передать ему вывод Document.getElementsByTagName
Это возвращает список узлов DOM.
изначально я думал использовать что-то простое, как:
Array.prototype.slice.call(list,0)
и это отлично работает во всех браузерах, за исключением, конечно, Internet Explorer, который возвращает ошибку "ожидаемый объект JScript" , поскольку, по-видимому, список узлов DOM возвращается Document.getElement*
methods не является объектом JScript достаточно, чтобы быть целью вызова функции.
предостережения: я не против написания определенного кода Internet Explorer, но мне не разрешено использовать любые библиотеки Javascript, такие как JQuery, потому что я пишу виджет, который будет встроен в сторонний веб-сайт, и я не могу загружать внешние библиотеки, которые создадут конфликт для клиентов.
мое последнее усилие состоит в том, чтобы перебирать список узлов DOM и создавать массив самостоятельно, но есть ли более приятный как это сделать?
7 ответов:
NodeLists являются для размещения объектов, С помощью
Array.prototype.slice
метод на объектах хоста не гарантируется, спецификация ECMAScript гласит:возможность успешного применения функции среза к объекту хоста зависит от реализации.
Я бы рекомендовал вам сделать простую функцию для итерации по
NodeList
и добавить каждый существующий элемент массива:function toArray(obj) { var array = []; // iterate backwards ensuring that length is an UInt32 for (var i = obj.length >>> 0; i--;) { array[i] = obj[i]; } return array; }
на es6 вы можете просто использовать следующим образом:
распространение оператор
var elements = [... nodelist]
используя
Array.from
var elements = Array.from(nodelist)
дополнительная ссылка на https://developer.mozilla.org/en-US/docs/Web/API/NodeList
используя распространение (ES2015), это так же просто, как:
[...document.querySelectorAll('p')]
(опционально: использование Бабель чтобы транспилировать приведенный выше код ES6 в синтаксис ES5)
попробуй в консоли вашего браузера и увидеть волшебство:
for( links of [...document.links] ) console.log(links);
используйте этот простой трюк
<Your array> = [].map.call(<Your dom array>, function(el) { return el; })
хотя это не совсем правильная прокладка, поскольку нет спецификации, требующей работы с элементами DOM, я сделал ее, чтобы вы могли использовать
slice()
таким образом:https://gist.github.com/brettz9/6093105обновление: когда я поднял это с редактором спецификации DOM4 (спрашивая, могут ли они добавить свои собственные ограничения для размещения объектов (так что спецификация потребует от исполнителей правильно конвертировать эти объекты при использовании с массивом методы) за пределами спецификации ECMAScript, которая позволила реализовать независимость), он ответил, что " объекты Хоста более или менее устарели для ES6 / IDL.- Я вижу Пер http://www.w3.org/TR/WebIDL/#es-array что спецификации могут использовать этот IDL для определения "объектов массива платформы", но http://www.w3.org/TR/domcore/ похоже, не использует новый IDL для
HTMLCollection
(хотя похоже, что это может быть сделано дляElement.attributes
хотя он только явно заявляет, что использует WebIDL для DOMString и DOMTimeStamp). Я вижу[ArrayClass]
(который наследует от массива.прототип) используется дляNodeList
(иNamedNodeMap
теперь устарел в пользу единственного элемента, который все еще будет использовать его,Element.attributes
). В любом случае, похоже, что это должно стать стандартом. В ЕС6Array.from
также может быть удобнее для таких преобразований, чем указыватьArray.prototype.slice
и более семантически понятно, чем[].slice()
(и более короткая форма,Array.slice()
("массив generic"), насколько я знаю, не стал стандартное поведение.)
var arr = new Array(); var x= ... get your nodes; for (i=0;i<x.length;i++) { if (x.item(i).nodeType==1) { arr.push(x.item(i)); } }
Это должно работать, кросс-браузер и получить вам все узлы "элемент".
сегодня, в 2018 году, мы могли бы использовать ECMAScript 2015 (6-е издание) или ES6, но не все браузеры могут понять его (например. Т. е. не понимает всего этого). Если вы хотите, вы можете использовать ES6 следующим образом:
var array = [... NodeList];
(как оператор распространения) илиvar array = Array.from(NodeList);
.в другом случае (если вы не можете использовать ES6) вы можете использовать самый короткий способ преобразования
NodeList
кArray
:
var array = [].slice.call(NodeList, 0);
.например:
var nodeList = document.querySelectorAll('input'); //we use "{}.toString.call(Object).slice(8, -1)" to find the class name of object console.log({}.toString.call(nodeList).slice(8, -1)); //NodeList var array = [].slice.call(nodeList, 0); console.log({}.toString.call(array).slice(8, -1)); //Array var result = array.filter(function(item){return item.value.length > 5}); for(var i in result) console.log(result[i].value); //credit, confidence
<input type="text" value="trust"><br><br> <input type="text" value="credit"><br><br> <input type="text" value="confidence">
но если вы хотите перебирать
DOM
список узлов легко, то вам не нужно преобразоватьNodeList
доArray
. Это можно перебирать элементы вNodeList
использование:var nodeList = document.querySelectorAll('input'); // Calling nodeList.item(i) isn't necessary in JavaScript for(var i = 0; i < nodeList.length; i++) console.log(nodeList[i].value); //trust, credit, confidence
<input type="text" value="trust"><br><br> <input type="text" value="credit"><br><br> <input type="text" value="confidence">
не поддавайтесь искушению использовать
for...in
илиfor each...in
для перечисления элементов в списке, так как это также перечислит длину и свойства элементаNodeList
и вызывают ошибки, если ваш скрипт предполагает, что он имеет дело только с объектами элементов. Кроме того,for..in
не гарантируется посещение свойств в каком-либо определенном порядке.for...of
циклы будут правильно перебирать объекты NodeList.посмотреть тоже: