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

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

问题描述

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

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

颜色参数示例:

var color_btns = document.querySelectorAll('#color > p');color_btns.forEach(功能(颜色){color.onclick = function () {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 并且效果很好,

  • 但我怎样才能让它发挥作用?
  • Internet ExplorerforEach() 是否有特定用途?边缘 ?

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

解决方案

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

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

NodeListHTMLCollection 都是 iterable,这意味着您可以使用 for-of,通过扩展([...theCollection])等将它们扩展为数组.但是如果您在 NodeList 没有 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它是一个价值属性.(enumerabletrue 让我感到惊讶,但这就是它在 Chrome/Chromium/Edge/Etc.、Firefox、旧版 Legacy Edge 和 Safari 上的原生定义方式.p>

在您自己的代码中,您也可以根据需要使用 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 上运行功能日志(){如果(控制台类型!==未定义"&& console.log){console.log.apply(控制台,参数);}}if (typeof NodeList !== "undefined" && NodeList.prototype) {//forEachif (!NodeList.prototype.forEach) {//是的,这里真的不需要 `Object.defineProperty`console.log("已添加 forEach");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],可写:真,可配置:真});}}log("测试每个");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 class="container"><div>一个</div><div>两个</div><div>三个</div><div>四个</div></div>


¹这很令人困惑,因为 HTMLCollection 是可迭代的,但它不是标有 iterable 声明,奇怪的是在 JavaScript DOM 绑定中并不意味着某些东西是可迭代的,它意味着它有 forEach, entries, keys, values, and 它是可迭代的.但是没有用 iterable 声明标记的 HTMLCollection 仍然是可迭代的.相反,它是可迭代的,因为如前所述的 这个 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.

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

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