getElementsByTagName returns 包含空元素的数组

getElementsByTagName returns array with null elements

我有这个 Tampermonkey 脚本:

// ==UserScript==
// @name         Remove strong tags
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  remove answers
// @author       You
// @match        http://*/*
// @grant        GM_log
// @run-at       document-end
// ==/UserScript==

setTimeout((function() {
    'use strict';

    var allStrong = document.getElementsByTagName("strong");
    GM_log(allStrong);

    for (var i=0, max=allStrong.length; i < max; i++) {
        var strong = allStrong.item(i);
        GM_log(strong);
        if(strong && strong.parentNode.tagName == "LI") {
            strong.parentNode.appendChild(strong.firstChild);
            strong.parentNode.removeChild(strong);
        }
    }
})(), 5000);

在符合条件的 8 个 strong 个标签中,它只替换了 4 个。

这在 Chrome 控制台中打印。

第一次打印的数组有 8 个元素,但最后 4 个元素打印为 undefined

为什么会这样?

我不认为问题出在整个页面加载之前正在执行的代码,因为我设置了很大的超时时间。

This 是我所在的页面 运行 它。

第一个打印输出显示了 8 个元素,因为它就是当时的样子。但它是一个 HTMLCollection,并且在 HTML DOM 中它是实时的;它会在基础文档更改时自动更新。

for 循环删除了其中一些 <strong> 节点 (strong.parentNode.removeChild(strong);),但只在开始时评估集合的长度 (max=allStrong.length)。所以它仍然会 运行 8 次,但是当它达到一半时,它就什么都不迭代了。

当您 展开 第一行日志时,Chrome 评估您的实时 HTML 集合,到那时它只包含 4 个元素,因此它仅显示 4。行尾的小 (i) 告诉您此表达式的计算时间。

如果您想实时查看所有这些内容,而不是将其放在 setTimeout 中,我建议您在代码中添加以下语句,无论您想在何处开始查看它一步一步:

debugger;

getElementsByTagName returns 所谓的实时 NodeList,而不是静态 Array - 这意味着它包含您的查询的最新结果。

因此,在每次迭代之后,其中一个元素将被删除,因为它不再是 <strong> 元素。

您有 2 个选择:

  • NodeList 转换为正常的 Array(例如,使用 Array.from
  • 始终访问 NodeList
  • 的第一个元素