我正在编写一个简短的脚本来更改<abbr>
元素的内部文本,但发现nodelist
没有forEach
方法。我知道nodelist
不会从Array
继承,但看起来forEach
似乎不是一个有用的方法吗?我不知道是否存在阻止将forEach
添加到nodelist
的特定实施问题?
注意:我知道Dojo和jQuery的节点列表都有某种形式的forEach
。由于限制,我无法使用。
答案 0 :(得分:82)
这些答案都没有解释为什么 NodeList不会从Array继承,从而允许它拥有forEach
以及所有其余的。
答案是on this es-discuss thread。简而言之,它破坏了网络:
问题是代码错误地假定instanceof意味着该实例是与Array.prototype.concat结合使用的Array。
Google的Closure Library中存在一个错误,导致几乎所有Google的应用都因此而失败。一旦发现这个库就更新了库但是可能仍然有代码与concat结合使用相同的错误假设。
也就是说,有些代码做了像
这样的事情if (x instanceof Array) {
otherArray.concat(x);
} else {
doSomethingElseWith(x);
}
然而,concat
会对待&#34;真实&#34;数组(不是instanceof Array)与其他对象不同:
[1, 2, 3].concat([4, 5, 6]) // [1, 2, 3, 4, 5, 6]
[1, 2, 3].concat(4) // [1, 2, 3, 4]
这意味着当x
是一个NodeList时,上面的代码就破了,因为它在doSomethingElseWith(x)
路径下降之前,然后它沿着otherArray.concat(x)
路径向下走,它做了一些事情很奇怪,因为x
并不是真正的数组。
有一段时间,有一个Elements
类的提议,它是Array的一个真正的子类,并将被用作&#34;新的NodeList&#34;。但是,至少就目前来说,这是removed from the DOM Standard,因为出于各种技术和规范相关的原因而实施它是不可行的。
答案 1 :(得分:52)
你可以做到
Array.prototype.forEach.call (nodeList, function (node) {
// Your code here.
} );
答案 2 :(得分:32)
您可以考虑创建一个新的节点数组。
var nodeList = document.getElementsByTagName('div'),
nodes = Array.prototype.slice.call(nodeList,0);
// nodes is an array now.
nodes.forEach(function(node){
// do your stuff here.
});
注意:这只是我们在这里创建的节点引用的列表/数组,没有重复的节点。
nodes[0] === nodeList[0] // will be true
答案 3 :(得分:18)
永远不要说永远,它是2016年,NodeList
对象在最新的chrome(v52.0.2743.116)中实现了forEach
方法。
在生产中使用它还为时过早,因为其他浏览器尚不支持此功能(经过测试的FF 49),但我猜这很快就会标准化。
答案 4 :(得分:16)
简而言之,实现该方法存在设计冲突。
来自MDN:
为什么我不能在NodeList上使用forEach或map?
NodeList与数组非常相似,而且很有吸引力 对它们使用Array.prototype方法。但是,这是不可能的。
JavaScript具有基于原型的继承机制。排列 实例继承数组方法(例如forEach或map)因为它们的 原型链如下所示:
myArray --> Array.prototype --> Object.prototype --> null
( 可以通过多次调用获得对象的原型链 Object.getPrototypeOf)forEach,map等都是Array.prototype的属性 对象
与数组不同,NodeList原型链如下所示:
myNodeList --> NodeList.prototype --> Object.prototype --> null
NodeList.prototype包含item方法,但没有 Array.prototype方法,因此它们不能在NodeLists上使用。
来源:https://developer.mozilla.org/en-US/docs/DOM/NodeList(向下滚动到为什么我不能在NodeList上使用forEach或map?)
答案 5 :(得分:13)
如果您想在NodeList上使用forEach,只需从Array中复制该函数:
NodeList.prototype.forEach = Array.prototype.forEach;
多数,现在您可以像对阵Array一样使用它:
document.querySelectorAll('td').forEach(function(o){
o.innerHTML = 'text';
});
答案 6 :(得分:4)
在ES2015中,您现在可以使用forEach
方法到nodeList。
document.querySelectorAll('abbr').forEach( el => console.log(el));
请参阅MDN Link
但是,如果要使用HTML集合或其他类似数组的对象,则在es2015中,您可以使用Array.from()
方法。此方法采用类似数组或可迭代的对象(包括nodeList,HTML Collections,字符串等)并返回一个新的Array实例。您可以像这样使用它:
const elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( el => console.log(el));
由于Array.from()
方法是可调的,您可以在es5代码中使用它,如
var elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( function(el) {
console.log(el);
});
有关详细信息,请参阅MDN页。
或强>
另一种es2015方式是使用扩展运算符。
[...document.querySelectorAll('abbr')].forEach( el => console.log(el));
答案 7 :(得分:2)
我的解决方案:
//foreach for nodeList
NodeList.prototype.forEach = Array.prototype.forEach;
//foreach for HTML collection(getElementsByClassName etc.)
HTMLCollection.prototype.forEach = Array.prototype.forEach;
答案 8 :(得分:0)
NodeList是DOM API的一部分。查看适用于JavaScript的ECMAScript绑定。 http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html。 nodeList和只读length属性以及item(index)函数返回一个节点。
答案是,你必须迭代。没有替代。 Foreach不起作用。 我使用Java DOM API绑定并遇到同样的问题。
答案 9 :(得分:0)
检查MDN是否符合NodeList.forEach规范。
NodeList.forEach(function(item, index, nodeList) {
// code block here
});
在IE中,使用akuhn's answer:
[].forEach.call(NodeList, function(item, index, array) {
// code block here
});