forSeach querySelectorAll在最近的Microsoft浏览器中不起作用

Aym*_*Dev 7 javascript arrays foreach internet-explorer microsoft-edge

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

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

颜色参数的示例:

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;
    };
});
Run Code Online (Sandbox Code Playgroud)

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

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

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

我用一个替换.forEachfor它,它工作得很好,

  • 但是我怎么能让它发挥作用呢?
  • 是否有forEach()针对Internet ExplorerEdge的特定用法?

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

T.J*_*der 18

返回值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;
}
Run Code Online (Sandbox Code Playgroud)

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


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

在实践中,具有使用可迭代性(如for-of循环)的功能的浏览器也可能已经提供了这些功能NodeList,但为了确保(可能是您正在进行转换并包含polyfill Symbol),我们需要做一秒钟thing:向其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
    });
}
Run Code Online (Sandbox Code Playgroud)

两者兼顾:

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
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个使用两者的实例,尝试使用(例如)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"; ' +
        '}'
    );
}
Run Code Online (Sandbox Code Playgroud)
<div class="container">
  <div>one</div>
  <div>two</div>
  <div>three</div>
  <div>four</div>
</div>
Run Code Online (Sandbox Code Playgroud)


Ali*_*eza 5

好的,让我们从这里开始,在JavaScript中,有些情况我们称之为Array-like,这意味着即使它看起来像一个数组,它也不是真正的数组...

例如函数中的参数或您所用的节点列表 ...

甚至所有现代的浏览器都知道您想要将其更改为Array并正常运行,例如在IE和其他一些浏览器中,使用Nodelist上的数组函数也不支持...

因此,如果您支持广泛的浏览器,最好在对其进行任何活动之前将它们转换为数组...

有几种方法可以将类似数组的值转换为实际的数组 ...

ES5中广泛使用的一种结构是:

Array.prototype.slice.call(YourNodeList);

因此,您可以执行以下操作:

var allDivs = document.querySelectorAll("div");
var allRealDivsArray = Array.prototype.slice.call(allDivs);
Run Code Online (Sandbox Code Playgroud)

但是,如果您使用ES6,甚至可以使用更巧妙的方法,例如,请确保使用babel将它们转换为ES5,因为那些不支持像数组一样循环的旧浏览器肯定也不会支持ES6。 ..

两种非常常见的方法是:

1)使用Array.from

const allDivs = document.querySelectorAll("div");
const allRealDivsArray = Array.from(allDivs);
Run Code Online (Sandbox Code Playgroud)

2)使用[... Array]

const allDivs = document.querySelectorAll("div");
const allRealDivsArray = [...allDivs];
Run Code Online (Sandbox Code Playgroud)