如何将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)); } }
这应该工作,跨浏览器,让你所有的“元素”节点。