Подтвердить что ты не робот

Как преобразовать список 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 и создать массив самостоятельно, но есть ли лучший способ сделать это?

4b9b3361

Ответ 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 вы можете просто использовать следующее:

  • Оператор распространения

     var elements = [... nodelist]
    
  • Использование Array.from

     var elements = Array.from(nodelist)
    

больше ссылок на 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) используется для NodeListNamedNodeMap теперь устарел в пользу единственного элемента, который все еще будет его использовать, 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">