我有一个接受HTML节点列表的Javascript函数,但是它需要一个Javascript数组(它在那里运行一些Array方法)并且我想为它提供返回DOM节点的Document.getElementsByTagName
的输出列表。
最初我想过使用简单的东西:
Array.prototype.slice.call(list,0)
并且在所有浏览器中都可以正常工作,当然Internet Explorer会返回错误“JScript object expected”,因为显然Document.getElement*
方法返回的DOM节点列表不是足以成为目标的JScript对象函数调用。
警告:我不介意编写Internet Explorer特定的代码,但我不允许使用任何Javascript库,如JQuery,因为我正在编写一个嵌入第三方网站的小部件,我无法加载外部库会给客户造成冲突。
我最后的努力是迭代DOM节点列表并自己创建一个数组,但是有更好的方法吗?
答案 0 :(得分:108)
在 es6 中,您可以按如下方式使用:
传播运营商
var elements = [... nodelist]
使用Array.from
var elements = Array.from(nodelist)
答案 1 :(得分:45)
NodeLists是 host objects ,在主机对象上使用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
method natively,所以如果你在一个现代化的环境,你可以直接使用它,或者有一个pollyfill。
答案 2 :(得分:16)
[...document.querySelectorAll('p')]
(可选:使用Babel将上述ES6代码转换为ES5语法)
在浏览器的控制台中试一试,看看魔术:
for( links of [...document.links] )
console.log(links);
答案 3 :(得分:9)
使用这个简单的技巧
<Your array> = [].map.call(<Your dom array>, function(el) {
return el;
})
答案 4 :(得分:6)
虽然它不是一个真正的垫片,因为没有规范要求使用DOM元素,我已经做了一个允许你以这种方式使用slice()
:https://gist.github.com/brettz9/6093105
UPDATE :当我使用DOM4规范的编辑器提出这个问题时(询问他们是否可以将自己的限制添加到宿主对象中(因此规范要求实施者在使用时正确转换这些对象)除了允许实现独立的ECMAScript规范之外的数组方法),他回答说“每个ES6 / IDL主机对象或多或少已经过时”。我看到每个http://www.w3.org/TR/WebIDL/#es-array规范可以使用此IDL来定义“平台数组对象”,但http://www.w3.org/TR/domcore/似乎没有使用HTMLCollection
的新IDL(尽管它看起来可能如此)正在为Element.attributes
这样做,尽管它只是明确声明它正在使用WebIDL用于DOMString和DOMTimeStamp)。我确实看到[ArrayClass]
(继承自Array.prototype)用于NodeList
(而且NamedNodeMap
现在已被弃用,以支持仍然使用它的唯一项目,{{1 }})。无论如何,看起来它是标准的。对于此类转换,ES6 Element.attributes
也可能比指定Array.from
更加方便,且语义清晰度高于Array.prototype.slice
(以及更短的格式[].slice()
(“数组通用” “),据我所知,并没有成为标准行为。)
答案 5 :(得分:3)
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));
}
}
这应该可以工作,跨浏览器并获取所有“元素”节点。
答案 6 :(得分:3)
今天,在2018年,我们可以使用ECMAScript 2015(第6版)或ES6,但并非所有浏览器都可以理解(例如,IE不能完全理解)。如果需要,可以按以下方式使用ES6:
var array = [... NodeList];
( as spread operator )或 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对象。
也请参见: