Как преобразовать список узлов 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 64

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] (который наследует от массива.прототип) используется для NodeListNamedNodeMap теперь устарел в пользу единственного элемента, который все еще будет использовать его, Element.attributes). В любом случае, похоже, что это должно стать стандартом. В ЕС6 Array.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.

посмотреть тоже: