如果我在for语句中使用object.getElementsByTagName(tagName)
,
for (index = 0; index < object.getElementsByTagName(tagName).length; index++) {
object.getElementsByTagName(tagName)[index].property = value;
}
浏览器是否为每次循环实例化实例化一个新的nodeList对象,或者浏览器是否每次只引用一个生成的列表;或者,它可以实例化一个列表,引用指定的对象并在每次通过循环时卸载列表对象?
我一直想知道将nodeList对象存储到变量是否更好,并在需要时引用它。
答案 0 :(得分:1)
浏览器是否为每次循环实例化实例化一个新的nodeList对象,或者浏览器是否每次只引用一个生成的列表;
您可以通过测试对getElementsByTagName
的两次调用是否返回同一对象来轻松测试:
document.getElementsByTagName('div') === document.getElementsByTagName('div')
// true
似乎使用相同的参数调用此方法确实会返回相同的NodeList
对象(至少在Firefox和Chrome中)。 每次都不会生成新列表。
所以你可能会认为一遍又一遍地在循环中调用它不会有所作为。但是,正如我所看到的,有多种原因可以将列表存储在变量中:
每个循环都有一个不必要的函数调用。
你不知道幕后究竟发生了什么。即使返回相同的对象,也可能是正在运行的过程,这些过程确保列表反映了文档的当前状态,如果您没有调用该函数,则不会发生这种情况。
最重要的是:The DOM specification似乎并不要求返回相同的列表。它在Firefox和Chrome(我测试过它)中可能只是一个实现细节,所以我不会依赖这种行为。实际上,规范明确规定返回 new 列表:
返回值:包含所有匹配元素的新NodeList对象。
我一直想知道将nodeList对象存储到变量是否更好,并在需要时引用它。
是的。添加或删除元素时甚至不必再次调用getElementsByTagName
,因为返回的NodeList
实时,即对文档所做的任何更改都会直接反映在列表,没有你明确更新
某些操作(如访问列表的length
)也会触发重新评估。因此,除了将列表存储在变量中之外,您可能还希望缓存长度:
var nodes = object.getElementsByTagName(tagName);
for (var index = 0, l = nodes.length; index < l; index++) {
nodes[index].property = value;
}
根据您的需要,这可能非常方便或非常混乱。如果您只想要调用函数时存在的节点列表,则必须将NodeList转换为数组:
var nodes = Array.prototype.slice.call(object.getElementsByTagName(tagName), 0);
答案 1 :(得分:1)
这是更好的代码,原因如下:
var elems = object.getElementsByTagName(tagName);
for (var index = 0, len = elems.length; index < len; index++) {
elems[index].property = value;
}
getElementsByTagName()
。它只获取一次nodeList。答案 2 :(得分:0)
您的浏览器每次都会生成一个新列表。
但是这段代码将在index
改变每次运行时起作用。
首先在某些var
中保存节点列表是个好习惯:
var elements = object.getElementsByTagName(tagName);
for (index = 0; index < elements; index++) {
elements[index].property = value;
}
你可以看到你的aproach:
var index = 0;
while(index<object.getElementsByTagName(tagName))
{
elements[index].property = value;
index++;
}
答案 3 :(得分:0)
这个测试显示它首先得到数组每次计算长度!
var testObj = {
getArray: function () {
console.log( 'getting array' );
return this._array;
},
_array: ['a','b','c']
};
for ( var index = 0; index < testObj.getArray().length; index++ ){
document.write( testObj.getArray()[index] );
}
我要先存储元素,每次都引用它的.length,或者只是将长度存储在变量中:)
答案 4 :(得分:0)
您期望它做什么?读你的想法?您是否期望JS处理器具有object.getElementsByTagName(tagName)
每次调用时(可能)返回相同值的语义信息,因此是“循环不变”,因此可以从循环中提升(参见循环) http://en.wikipedia.org/wiki/Loop-invariant_code_motion)?
也许你想象浏览器以某种方式“缓存”元素下具有特定标记名的所有元素的列表,然后在后续调用中返回相同的列表?虽然很难在没有查看代码的情况下判断浏览器在做什么,但可能不是,或者一个浏览器可能是另一个浏览器而不是。即使浏览器确实缓存了结果,也认为在整个方案中任何性能损失可能都很小,一次又一次地调用API将总是比引用已经设置的变量的效率低得多。对节点列表的每个元素执行的操作(例如设置属性)可能会导致重置缓存,这并非不可能。
作为一个小问题,假设列表是一遍又一遍地创建的,那么它就不会被“卸载”; JS中没有这样的概念。从技术角度来说,它的地位将“只是坐在那里”。很快就会收集垃圾。
所以是的,一定要只调用getElementsByTagName
一次。实际上,你可以在你的程序开始时调用它一次(假设你只有一个你感兴趣的对象和标记名),因为它返回一个“实时”列表。请参阅https://developer.mozilla.org/en-US/docs/Web/API/element.getElementsByTagName。