我当时正在编写一个简短的脚本来更改<abbr>
元素的内部文本,但是发现它nodelist
没有forEach
方法。我知道那nodelist
不是继承自Array
,但似乎不是forEach
一种有用的方法吗?是否有一个具体的实施问题,我不知道阻止添加的forEach
到nodelist
?
注意:我知道Dojo和jQuery forEach
的节点列表都有某种形式。由于限制,我无法使用任何一个。
Answers:
这些答案都不能解释为什么 NodeList不继承自Array,从而允许它拥有forEach
其余所有内容。
答案在此es-discuss线程上找到。简而言之,它破坏了网络:
问题是代码错误地将instanceof假定为实例是与Array.prototype.concat结合使用的Array。
Google的Closure库中存在一个错误,由于该错误,几乎所有Google的应用程序都失败了。发现该库后即会对其进行更新,但在那里可能仍然存在与concat结合使用时做出相同错误假设的代码。
也就是说,某些代码做了类似的事情
if (x instanceof Array) {
otherArray.concat(x);
} else {
doSomethingElseWith(x);
}
但是,concat
将“实际”数组(不是instanceof数组)与其他对象区别对待:
[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的真正子类,将被用作“新的NodeList”。但是,至少从现在起,它已从DOM标准中删除,因为由于各种技术和规范相关的原因,尚不可行。
NodeList now has forEach() in all major browsers
似乎暗示IE不是主要的浏览器。希望对某些人来说是正确的,但对我来说还不正确。
你可以做
Array.prototype.forEach.call (nodeList, function (node) {
// Your code here.
} );
Array.prototype.forEach.call
可以[].forEach.call
Array.prototype.forEach.call
,它还在创建一个空数组并使用其forEach
方法。
您可以考虑创建一个新的节点数组。
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
Array.prototype.forEach.call(nodeList, fun)
。
var forEach = Array.prototype.forEach.call(nodeList, callback);
。现在您可以简单地致电forEach(nodeList, callback);
简而言之,实现该方法存在设计冲突。
从MDN:
为什么我不能在节点列表上使用forEach或映射?
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(向下滚动至为什么我不能使用forEach或在NodeList上进行映射?)
myNodeList --> NodeList.prototype --> Array.prototype --> Object.prototype --> null
?
如果要在NodeList上使用forEach,只需从Array复制该函数:
NodeList.prototype.forEach = Array.prototype.forEach;
就是这样,现在您可以以与Array相同的方式使用它:
document.querySelectorAll('td').forEach(function(o){
o.innerHTML = 'text';
});
在ES2015中,您现在forEach
可以对nodeList 使用method。
document.querySelectorAll('abbr').forEach( el => console.log(el));
请参阅MDN链接
但是,如果要使用HTML集合或其他类似数组的对象,则在es2015中可以使用Array.from()
method。此方法采用类似数组的对象或可迭代的对象(包括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));
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绑定,并且遇到相同的问题。
检查MDN以获取NodeList.forEach规范。
NodeList.forEach(function(item, index, nodeList) {
// code block here
});
在IE中,使用akuhn的答案:
[].forEach.call(NodeList, function(item, index, array) {
// code block here
});