У меня есть функция Javascript, которая принимает список узлов HTML, но ожидает массив Javascript (он запускает для него некоторые методы Array), и я хочу передать ему результат, Document.getElementsByTagName
который возвращает список узлов DOM.
Сначала я подумал об использовании чего-нибудь простого, например:
Array.prototype.slice.call(list,0)
И это прекрасно работает во всех браузерах, за исключением, конечно, Internet Explorer, который возвращает ошибку «Ожидается объект JScript», поскольку очевидно, что список узлов DOM, возвращаемый Document.getElement*
методами, не является объектом JScript, достаточным для того, чтобы быть целью вызова функции.
Предостережения: я не возражаю против написания кода для Internet Explorer, но мне не разрешено использовать какие-либо библиотеки Javascript, такие как JQuery, потому что я пишу виджет для встраивания в сторонний веб-сайт, и я не могу загружать внешние библиотеки, которые создаст конфликт для клиентов.
Моя последняя неудачная попытка - перебрать список узлов DOM и создать массив самостоятельно, но есть ли способ сделать это лучше?
источник
Ответы:
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 в массив - это итерация по нему, и теперь
NodeList.prototype
объект имеетforEach
метод изначально , поэтому, если вы находитесь в современной среде, вы можете использовать его напрямую или иметь поллифилл.источник
array[i] = obj[i]
вместоarray.push(obj[i])
?obj.length
быть что-то другое, кроме целочисленного значения?В es6 вы можете просто использовать следующее:
Оператор распространения
var elements = [... nodelist]
С помощью
Array.from
var elements = Array.from(nodelist)
дополнительная информация на https://developer.mozilla.org/en-US/docs/Web/API/NodeList
источник
Array.from()
: DArray.from
работает только , поскольку TS передает этоnodelist.slice
- что не поддерживается.Array.from
spread
используется.Используя распространение (ES2015) , это так же просто, как:
[...document.querySelectorAll('p')]
(необязательно: используйте Babel для преобразования вышеуказанного кода ES6 в синтаксис ES5)
Попробуйте в консоли своего браузера и убедитесь в волшебстве:
for( links of [...document.links] ) console.log(links);
источник
Используйте этот простой трюк
<Your array> = [].map.call(<Your dom array>, function(el) { return el; })
источник
Array.prototype.slice
(или,[].slice
как вы это выразились)? В качестве примечания я хотел бы прокомментировать, что специфическая ошибка IE, которую я задокументировал в Q, происходит в IE 8 или ниже, гдеmap
она все равно не реализована. В IE 9 («стандартный режим») или выше обаslice
иmap
работают одинаково.Хотя на самом деле это не подходящая прокладка, поскольку нет спецификации, требующей работы с элементами 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]
(который наследуется от Array.prototype) используется дляNodeList
(иNamedNodeMap
теперь устарел в пользу единственного элемента, который все еще будет его использоватьElement.attributes
). В любом случае, похоже, он станет стандартом. ES6Array.from
также может быть более удобен для таких преобразований, чем необходимость указыватьArray.prototype.slice
и более семантически понятный, чем[].slice()
(и более короткая формаArray.slice()
(«универсальный массив»), насколько мне известно, не стала стандартным поведением).источник
Сегодня, в 2018 году, мы могли бы использовать ECMAScript 2015 (6-е издание) или ES6, но не все браузеры могут его понять (например, IE понимает не все). Если вы хотите, вы можете использовать ES6 следующим образом:
var array = [... NodeList];
( как оператор распространения ) илиvar array = Array.from(NodeList);
.В другом случае (если вы не можете использовать ES6) вы можете использовать кратчайший способ преобразовать a
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
список узлов, вам не нужно преобразовывать aNodeList
в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.Смотрите также:
источник
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)); } }
Это должно работать, кроссбраузерно и получить все узлы «элемента».
источник