forEach on querySelectorAll 在最近的 Microsoft 浏览器中不起作用 [英] forEach on querySelectorAll not working in recent Microsoft browsers

查看:22
本文介绍了forEach on querySelectorAll 在最近的 Microsoft 浏览器中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个用于选择产品(颜色等)的脚本,它适用于所有浏览器,除了 Internet Explorer (11) &边缘.

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

颜色参数示例:

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

我在 IE & 的控制台中得到以下输出边缘:

<块引用>

对象不支持forEach"属性或方法

搜索问题后,我了解到这个函数应该是IE 9 及更新版本支持.我试图自己定义函数但没有成功.当我记录函数时,它被定义为一个函数(里面有[native code]").

我用一个 for 替换了每个 .forEach 并且它工作得很好,

  • 但我怎样才能让它发挥作用?
  • 是否有 forEach() 用于 Internet Explorer 和的特定用法?边缘 ?

我以为是 Array.prototype.forEach 并且最近版本的 IE(以及所有版本的 Edge)都有它......?

解决方案

大多数 DOM 方法和集合属性实际上并不是数组,而是集合:

NodeList 最近才得到 forEach(以及 keys 和其他几个数组方法).HTMLCollection 没有也不会;事实证明,添加它们会破坏网络上的太多代码.

NodeListHTMLCollection 都是可迭代的,不过,这意味着您可以使用 for-of 遍历它们>,通过扩展 ([...theCollection]) 等将它们扩展为数组.但是如果您在 NodeList 没有 NodeList 的浏览器上运行code>forEach,它可能太老了,没有任何 ES2015+ 特性,如 for-of 或迭代.

由于 NodeList 被指定为具有 forEach,你可以安全地对它进行 polyfill,而且它真的很容易做到:

if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) {//是的,这里真的不需要 `Object.defineProperty`NodeList.prototype.forEach = Array.prototype.forEach;}

在这种情况下直接赋值没问题,因为enumerableconfigurablewritable都应该是true它是一个值属性.(enumerable 成为 true 令我感到惊讶,但这就是它在 Chrome/Chromium/Edge/Etc.、Firefox、旧版 Legacy Edge 和 Safari 上的原生定义方式.>

在你自己的代码中,如果你愿意,你也可以使用 HTMLCollection 来做到这一点,只是要注意,如果你使用的是一些旧的 DOM 库,比如 MooTools 或 YUI 等,它们可能是如果将 forEach 添加到 HTMLCollection 会感到困惑.


正如我之前所说,NodeListHTMLCollection 都被指定为可迭代的(因为 此 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, {值:Array.prototype[Symbol.itereator],可写:真实,可配置:真});}

(对于 HTMLCollection 也是如此.)

这是一个使用两者的现场示例,在(例如)IE11 上试试这个(虽然它只会演示 forEach),而 NodeList 没有这些功能原生:

//仅使用 ES5 功能,因此可在 IE11 上运行函数日志(){if (typeof console !== "undefined" && console.log) {console.log.apply(控制台,参数);}}if (typeof NodeList !== "undefined" && NodeList.prototype) {//forEach如果(!NodeList.prototype.forEach){//是的,这里真的不需要 `Object.defineProperty`console.log("为Each 添加");NodeList.prototype.forEach = Array.prototype.forEach;}//可迭代性 - 不会在 IE11 上发生,因为它没有 Symbolif (typeof Symbol !== "undefined" && Symbol.iterator && !NodeList.prototype[Symbol.iterator]) {console.log("添加Symbol.iterator");Object.defineProperty(NodeList.prototype, Symbol.iterator, {值:Array.prototype[Symbol.itereator],可写:真实,可配置:真});}}日志(测试每个");document.querySelectorAll(".container div").forEach(function(div) {var html = div.innerHTML;div.innerHTML = html[0].toUpperCase() + html.substring(1).toLowerCase();});//可迭代if (typeof Symbol !== "undefined" && Symbol.iterator) {//这里使用 eval 避免在 IE11 上导致语法错误log("测试可迭代性");评估('for (const div of document.querySelectorAll(".container div")) { ' +' div.style.color = "蓝色";' +'}');}

<div>一个</div><div>二</div><div>三</div><div>四</div>


¹ 令人困惑,因为 HTMLCollection 是可迭代的,但它没有标有 iterable 声明,奇怪的是在 JavaScript DOM 绑定中意味着某些东西是可迭代的,它意味着它有forEachentrieskeysvalues它是可迭代的.但是 HTMLCollection 没有用 iterable 声明标记,它仍然是可迭代的.相反,它是可迭代的,因为 这个 Web IDL 规则 如前所述.

I am making a script for choices about a product (colors etc), which works in every browser except for Internet Explorer (11) & Edge.

I put the choices of each parameter in a array and apply a function to them with the array.forEach() method.

Example for the color parameter:

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

I get the following output in the console of both IE & Edge:

Object doesn't support property or method 'forEach'

After searching about the issue, I learnt that this function should be supported by IE 9 and newer. I tried to define the function by myself without success. When I log the function it is defined as a function (with "[native code]" inside).

I replaced every .forEach by a for and it's working pretty well,

  • but how can I make it work ?
  • Is there a specific usage of the forEach() for Internet Explorer & Edge ?

I thought it was Array.prototype.forEach and that recent versions of IE (and all versions of Edge) had it...?

解决方案

Most DOM methods and collection properties aren't actually arrays, they're collections:

NodeList only recently got forEach (and keys and a couple of other array methods). HTMLCollection didn't and won't; it turned out adding them would break too much code on the web.

Both NodeList and HTMLCollection are iterable, though, meaning that you can loop through them with for-of, expand them into an array via spread ([...theCollection]), etc. But if you're running on a browser where NodeList doesn't have forEach, it's probably too old to have any ES2015+ features like for-of or iteration.

Since NodeList is specified to have forEach, you can safely polyfill it, and it's really easy to do:

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

Direct assignment is fine in this case, because enumerable, configurable, and writable should all be true and it's a value property. (enumerable being true surprised me, but that's how it's defined natively on Chrome/Chromium/Edge/Etc., Firefox, the old Legacy Edge, and Safari).

In your own code, you can do that with HTMLCollection as well if you want, just beware that if you're using some old DOM libs like MooTools or YUI or some such, they may be confused if you add forEach to HTMLCollection.


As I said before, NodeList and HTMLCollection are both specified to be iterable (because of this Web IDL rule¹). If you run into a browser that has ES2015+ features but doesn't make the collections iterable for some reason, you can polyfill that, too:

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

(And the same for HTMLCollection.)

Here's a live example using both, try this on (for instance) IE11 (although it will only demonstrate forEach), on which NodeList doesn't have these features natively:

// 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>


¹ It's confusing, because HTMLCollection is iterable but it isn't marked with the iterable declaration, which bizarrely in the JavaScript DOM bindings doesn't mean that something is iterable, it means that it has forEach, entries, keys, values, and it's iterable. But HTMLCollection, which isn't marked with the iterable declaration, is still iterable. Instead, it's iterable because of this Web IDL rule as mentioned earlier.

这篇关于forEach on querySelectorAll 在最近的 Microsoft 浏览器中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆