大多数 DOM 方法和集合属性实际上并不是数组,它们是集合:
NodeList最近才得到forEach(以及keys其他一些数组方法)。HTMLCollection没有也不会;事实证明,添加它们会破坏网络上的太多代码。
这两个NodeList和HTMLCollection的迭代,虽然,这意味着你可以遍历他们for-of,他们扩展到一个数组通过传播([...theCollection])等,但如果你在浏览器中运行,其中NodeList没有forEach,它可能太旧,有什么ES2015+ 等功能for-of或迭代。
由于NodeList被指定为 have forEach,您可以安全地对它进行 polyfill,而且很容易做到:
if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) {
    // Yes, there's really no need for `Object.defineProperty` here
    NodeList.prototype.forEach = Array.prototype.forEach;
}
在这种情况下,直接赋值很好,因为enumerable, configurable, 和writable都应该是true并且它是一个值属性。(enumerable这true让我感到惊讶,但这就是它在 Chrome/Chromium/Edge/Etc.、Firefox、旧的 Legacy Edge 和 Safari 上的本地定义方式)。
在你自己的代码中,HTMLCollection如果你愿意,你也可以这样做,只是要注意,如果你使用一些旧的 DOM 库,比如 MooTools 或 YUI 或其他类似的东西,如果你添加forEach到HTMLCollection.
正如我之前所说,NodeList并且HTMLCollection都被指定为可迭代的(因为这个 Web IDL 规则¹)。如果您遇到具有 ES2015+ 功能但由于某种原因不能使集合可迭代的浏览器,您也可以对其进行 polyfill:
if (typeof Symbol !== "undefined" && Symbol.iterator && typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype[Symbol.iterator]) {
    Object.defineProperty(NodeList.prototype, Symbol.iterator, {
        value: Array.prototype[Symbol.itereator],
        writable: true,
        configurable: true
    });
}
(对于HTMLCollection.也是如此。)
这是一个使用两者的现场示例,在(例如)IE11 上试试这个(虽然它只会演示forEach),它NodeList本身没有这些功能:
// Using only ES5 features so this runs on IE11
function log() {
    if (typeof console !== "undefined" && console.log) {
        console.log.apply(console, arguments);
    }
}
if (typeof NodeList !== "undefined" && NodeList.prototype) {
    // forEach
    if (!NodeList.prototype.forEach) {
        // Yes, there's really no need for `Object.defineProperty` here
        console.log("Added forEach");
        NodeList.prototype.forEach = Array.prototype.forEach;
    }
    // Iterability - won't happen on IE11 because it doesn't have Symbol
    if (typeof Symbol !== "undefined" && Symbol.iterator && !NodeList.prototype[Symbol.iterator]) {
        console.log("Added Symbol.iterator");
        Object.defineProperty(NodeList.prototype, Symbol.iterator, {
            value: Array.prototype[Symbol.itereator],
            writable: true,
            configurable: true
        });
    }
}
log("Testing forEach");
document.querySelectorAll(".container div").forEach(function(div) {
    var html = div.innerHTML;
    div.innerHTML = html[0].toUpperCase() + html.substring(1).toLowerCase();
});
// Iterable
if (typeof Symbol !== "undefined" && Symbol.iterator) {
    // Using eval here to avoid causing syntax errors on IE11
    log("Testing iterability");
    eval(
        'for (const div of document.querySelectorAll(".container div")) { ' +
        '    div.style.color = "blue"; ' +
        '}'
    );
}
<div class="container">
  <div>one</div>
  <div>two</div>
  <div>three</div>
  <div>four</div>
</div>
 
 
¹ 令人困惑,因为HTMLCollection它是可迭代的,但它没有用iterable声明标记,奇怪的是,在 JavaScript DOM 绑定中,这并不意味着某些东西是可迭代的,它意味着它具有forEach, entries, keys, values,并且它是可迭代的。但是HTMLCollection,没有用iterable声明标记的仍然是可迭代的。相反,由于前面提到的这个 Web IDL 规则,它是可迭代的。