如何在Javascript中将DOM节点列表转换为数组?

时间:2010-04-29 05:59:39

标签: javascript html dom

我有一个接受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节点列表并自己创建一个数组,但是有更好的方法吗?

7 个答案:

答案 0 :(得分:108)

es6 中,您可以按如下方式使用:

  • 传播运营商

     var elements = [... nodelist]
    
  • 使用Array.from

     var elements = Array.from(nodelist)
    

https://developer.mozilla.org/en-US/docs/Web/API/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)

使用spread (ES2015),它就像:[...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对象。

也请参见: