Как преобразовать список DOM node в массив в Javascript?
У меня есть функция Javascript, которая принимает список узлов HTML, но ожидает массив Javascript (на нем он запускает некоторые методы Array), и я хочу передать ему вывод Document.getElementsByTagName
, который возвращает DOM node список.
Первоначально я думал использовать что-то простое:
Array.prototype.slice.call(list,0)
И это прекрасно работает во всех браузерах, за исключением, конечно, Internet Explorer, который возвращает ошибку "ожидаемый объект JScript", поскольку, по-видимому, список DOM node, возвращаемый методами Document.getElement*
, не является объектом JScript, достаточным для того, чтобы быть целью вызова функции.
Предостережения: я не против писать специальный код Internet Explorer, но мне не разрешено использовать любые Javascript-библиотеки, такие как JQuery, потому что я пишу виджет, который будет встроен в сторонний веб-сайт, и я не могу загрузить внешние библиотеки, которые создадут конфликт для клиентов.
Мое последнее стремление - перебрать список DOM node и создать массив самостоятельно, но есть ли лучший способ сделать это?
Ответы
Ответ 1
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;
}
ОБНОВИТЬ:
Как показывают другие ответы, теперь вы можете использовать в современных средах синтаксис распространения или метод Array.from
:
const array = [ ...nodeList ] // or Array.from(nodeList)
Но, подумав об этом, я думаю, что наиболее распространенный вариант использования для преобразования NodeList в Array - это итерация по нему, и теперь объект NodeList.prototype
имеет метод forEach
изначально, поэтому, если вы находитесь в современной среде, вы можете использовать его напрямую или заполучить.
Ответ 2
В es6 вы можете просто использовать следующее:
больше ссылок на https://developer.mozilla.org/en-US/docs/Web/API/NodeList
Ответ 3
Используя распространение (ES2015), это так же просто, как: [...document.querySelectorAll('p')]
(необязательно: используйте Babel для преобразования приведенного выше кода ES6 в синтаксис ES5)
Попробуйте в консоли браузера и увидите волшебство:
for( links of [...document.links] )
console.log(links);
Ответ 4
Используйте этот простой трюк
<Your array> = [].map.call(<Your dom array>, function(el) {
return el;
})
Ответ 5
Хотя это не совсем правильная прокладка, так как нет спецификации, требующей работы с элементами DOM, я сделал один, чтобы вы могли использовать slice()
следующим образом: https://gist.github.com/brettz9/6093105
UPDATE. Когда я поднял это с помощью редактора спецификации DOM4 (спросив, могут ли они добавить свои собственные ограничения для объектов хоста (так, чтобы спецификация требовала, чтобы реализаторы правильно конвертировали эти объекты при использовании с методами массива) за пределами спецификации ECMAScript, которая позволила реализовать независимость), он ответил, что "Объекты хоста более или менее устарели в ES6/IDL". Я вижу per http://www.w3.org/TR/WebIDL/#es-array, что спецификации могут использовать этот IDL для определения "объектов массива платформы", но http://www.w3.org/TR/domcore/, похоже, не использует новый IDL для HTMLCollection
(хотя похоже, что он может сделать это для Element.attributes
, хотя он явно заявляет, что использует WebIDL для DOMString и DOMTimeStamp). Я вижу, что [ArrayClass]
(который наследуется от Array.prototype) используется для NodeList
(и NamedNodeMap
теперь устарел в пользу единственного элемента, который все еще будет его использовать, Element.attributes
). В любом случае, похоже, что он стал стандартным. ES6 Array.from
также может быть более удобным для таких преобразований, чем указание Array.prototype.slice
и более семантически прозрачное, чем [].slice()
(а более короткая форма Array.slice()
( "общий массив" ) имеет, насколько это возможно Я знаю, не становлюсь стандартным поведением).
Ответ 6
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));
}
}
Это должно работать, переходить через браузер и получать все узлы "элемента".
Ответ 7
Сегодня, в 2018 году, мы могли бы использовать ECMAScript 2015 (6-е издание) или ES6, но не все браузеры могут это понять (например, IE не понимает все это). Если вы хотите, вы можете использовать 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">