一尘不染

querySelectorAll上的forEach在最新的Microsoft浏览器中不起作用

javascript

我正在编写用于选择产品(颜色等)的脚本,该脚本可在除 Internet Explorer (11)和 Edge 之外的所有浏览器中使用。

我将每个参数的选择放入数组中,并使用方法将函数应用于它们array.forEach()

color参数的示例:

var color_btns = document.querySelectorAll('#color > p');
color_btns.forEach(function(color) {
    color.onclick = function () {
        color_btns.forEach(function(element) {
            if (element.classList.contains('selected')) {
                element.classList.remove('selected');
            }
        });
        color.classList.add('selected');
        document.querySelector('#f_color').value = color.dataset.id;
    };
});

我在 IEEdge 的控制台中都得到以下输出:

对象不支持属性或方法“ forEach”

搜索该问题后,我了解到IE9和更高版本应支持此功能。我尝试自己定义功能,但没有成功。当我登录该函数时,它被定义为一个函数([native code]内部带有“ ”)。

我用.forEacha 替换了每个,for效果很好,

  • 但是我如何使它工作呢?
  • 有没有的特定用途forEach()互联网浏览器边缘

我以为是Array.prototype.forEach这样,而IE的最新版本(以及Edge的所有版本)都拥有它…?


阅读 388

收藏
2020-04-25

共1个答案

一尘不染

返回值[querySelectorAll不是数组,而是NodeList。直到最近才有了forEach(并且与JavaScript的迭代协议兼容,让您将它们用作for-of和表示法的目标)。

您可以forEach轻松地填充:

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;
}

直接分配在这种情况下细,因为enumerableconfigurablewritable都应该true和它的价值属性。(enumerabletrue让我感到惊讶,但这是它是如何定义本身在Chrome,火狐,边缘和Safari)。


NodeListforEach,这也成了 迭代 ,这意味着你可以通过一个内容循环NodeList通过for- of回路,并使用NodeList(在数组初始化比如,在传播符号)在其他地方可迭代的预期。

在实践中,具有使用可迭代性的功能(例如for-of循环)的浏览器也可能已经提供的这些功能NodeList,但是要确保(也许您正在转码并包括的polyfillSymbol),我们需要再做一遍。事情:在其Symbol.iterator属性中添加一个函数以创建迭代器:

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
    });
}

一起做:

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;
    if (typeof Symbol !== "undefined" && Symbol.iterator && !NodeList.prototype[Symbol.iterator]) {
        Object.defineProperty(NodeList.prototype, Symbol.iterator, {
            value: Array.prototype[Symbol.itereator],
            writable: true,
            configurable: true
        });
    }
}

这是一个同时使用两者的实时示例,请在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

    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由归国getElementsByTagName(以及各种其他旧的API)没有被定义为可迭代的,但如果你喜欢,你也可以做到这一点的HTMLCollection为好。这是一个执行botyNodeList(如果需要)和HTMLCollection(如果需要)的循环:

for (const ctor of [typeof NodeList !== "undefined" && NodeList, typeof HTMLCollection !== "undefined" && HTMLCollection]) {
    if (ctor && ctor.prototype && !ctor.prototype.forEach) {
        // (Yes, there's really no need for `Object.defineProperty` here)
        ctor.prototype.forEach = Array.prototype.forEach;
        if (typeof Symbol !== "undefined" && Symbol.iterator && !ctor.prototype[Symbol.iterator]) {
            Object.defineProperty(ctor.prototype, Symbol.iterator, {
                value: Array.prototype[Symbol.itereator],
                writable: true,
                configurable: true
            });
        }
    }
}

请注意,这HTMLCollection是实时的,因此您对DOM进行的更改(影响集合中的内容)会立即反映在集合中,这可能会导致令人惊讶的行为。(NodeList是一个断开连接的集合,因此不会发生行为。)

2020-04-25