我有一个接受HTML节点列表的Javascript函数,但它需要一个Javascript数组(它运行一些数组方法),我希望它的输出Document.getElementsByTagName
返回一个DOM节点列表.
最初我想过使用简单的东西:
Array.prototype.slice.call(list,0)
这在所有浏览器中都可以正常工作,当然除了返回错误"JScript对象预期"的Internet Explorer,因为显然Document.getElement*
方法返回的DOM节点列表不是足以成为函数调用目标的JScript对象.
警告:我不介意编写Internet Explorer特定代码,但我不允许使用任何Javascript库,如JQuery,因为我正在编写一个嵌入第三方网站的小部件,我无法加载外部库会给客户造成冲突.
我最后的努力是迭代DOM节点列表并自己创建一个数组,但是有更好的方法吗?
在es6中你可以使用如下:
传播运营商
var elements = [... nodelist]
运用 Array.from
var elements = Array.from(nodelist)
更多参考资料来自https://developer.mozilla.org/en-US/docs/Web/API/NodeList
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; }
[...document.querySelectorAll('p')]
(可选:使用Babel将上面的ES6代码转换为ES5语法)
在浏览器的控制台中试一试,看看它的魔力:
for( links of [...document.links] ) console.log(links);
使用这个简单的技巧
= [].map.call( , function(el) { return el; })
虽然它不是一个真正的垫片,因为没有规范要求使用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
).无论如何,看起来它是标准的.Array.from
对于这样的转换,ES6 也可能比指定Array.prototype.slice
和更加语义清晰[].slice()
(并且更短的形式,Array.slice()
("数组通用")更方便,据我所知,它不会成为标准行为).
今天,在2018年,我们可以使用ECMAScript 2015(第6版)或ES6,但并非所有浏览器都可以理解它(例如,IE不能全部理解)。如果你愿意,你可以使用ES6如下:
var array = [... NodeList];
(为传播运营商)或var array = Array.from(NodeList);
。
在其他情况下(如果不能使用ES6),可以使用最短的方法将a转换NodeList
为an 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