如何将DOM节点列表转换为JavaScript中的数组?

我有一个Javascript函数接受HTML节点列表,但它期望一个Javascript数组(它运行一些数组方法),我想给它的Document.getElementsByTagName返回一个DOM节点列表的输出。

起初,我想到了使用简单的东西:

 Array.prototype.slice.call(list,0) 

这在所有浏览器中都能正常工作,当然,除了返回错误“JScript对象预期”的Internet Explorer,显然由Document.getElement*方法返回的DOM节点列表不是足够成为函数调用目标的JScript对象。

注意事项:我不介意编写Internet Explorer特定的代码,但是我不允许使用任何JavaScript库(如JQuery),因为我正在编写一个embedded第三方网站的小部件,而且我无法加载外部库会为客户造成冲突。

我最后的努力是迭代DOM节点列表并自己创build一个数组,但有没有更好的方法来做到这一点?

NodeLists是主机对象 ,使用主机对象上Array.prototype.slice方法不能保证能够工作,ECMAScript规范指出:

slice函数是否可以成功应用于主机对象取决于实现。

我build议你做一个简单的函数遍历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

使用ES6 传播 ,就像: [...document.querySelectorAll('p')]

(可选:使用Babel将上述ES6代码转换为ES5语法)


尝试在浏览器的控制台中看到魔法:

 for( p of [...document.links] ) console.log(p); 

虽然它不是一个真正的垫片,因为没有规范需要使用DOM元素,所以我已经允许你以这种方式使用slice() : https : //gist.github.com/brettz9/6093105

更新 :当我用DOM4规范的编辑器提出这个问题时(询问他们是否可以将自己的限制添加到主机对象(以便规范要求实现者在与数组方法一起使用时正确地转换这些对象)超出ECMAScript规范允许执行独立性),他回答说:“每个ES6 / IDL主机对象或多或less已经过时。 我看到每个http://www.w3.org/TR/WebIDL/#es-array规范可以使用这个IDL来定义“平台数组对象”,但http://www.w3.org/TR/domcore/ doesn似乎没有使用HTMLCollection的新IDL(虽然它看起来可能对Element.attributes这样做,尽pipe它只是明确指出它正在使用WebIDL来处理DOMString和DOMTimeStamp)。 我确实看到[ArrayClass] (它inheritance自Array.prototype)被用于NodeList (并且NamedNodeMap现在已经被弃用,只是仍然在使用它的Element.attributes )。 无论如何,它看起来是成为标准的。 ES6的Array.from可能也更方便的这种转换,而不是必须指定Array.prototype.slice和更多的语义清晰比[].slice() (和较短的forms, Array.slice() (“数组通用” ),据我所知,没有成为标准的行为)。

使用这个简单的技巧

 <Your array> = [].map.call(<Your dom array>, function(el) { return el; }) 
 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)); } } 

这应该工作,跨浏览器,让你所有的“元素”节点。