从控制台调用时,IE支持forEach(...),但从代码中调用时不支持。

9

我正在控制台中运行这段代码。在IE中,它产生了与预期完全相同的输出。在Cr和FF中运行相同的代码以进行参考确认其一致性。

["a", "b"].forEach(function(element) {
  console.log(element);
});

然而,当运行以下脚本时,我收到了错误提示,告诉我该对象上没有声明forEach(...)。这个问题在IE中出现,但在Cr和FF中没有。
var menus = document.querySelectorAll("ul.application>li>a");
menus.forEach(function(element) { ... }

我已经检查了变量 menus 的声明,并且选择它的元素产生了我所期望的结果,即 menus[0] 存在且是一个标记。在 IE 中看起来与其他浏览器有些不同,但这可能只是不同的渲染方式。
我很幸运能够使用 Cr 和 FF 工作,所以我的处理 IE 的经验有限。搜索也没有给我带来太多智慧。
我该如何进一步排除故障?

仅仅因为 NodeList 不是一个数组(而且 IE/Safari 不支持 NodeList.forEach,参见 MDN)。 - Adriano Repetti
据我所知,querySelectorAll返回的是一个HtmlCollection,而不是一个Array。Chrome可能在内部为此提供了一个polyfill,因此它可以在那里工作。 - Nope
1
那个“福利”也是一种诅咒 :) 当浏览器通过实现自己的内部解决方案来补偿时,它们会使IE看起来不正常,并且让您依赖于可能在未来版本中更改的自定义实现 :) 例如,不能保证Chrome将继续支持使用forEach扩展HtmlCollection,他们过去曾这样做 :) 尽管IE在很多方面都很糟糕,但如果您必须支持多个浏览器,包括特定版本的IE,则可能首先在IE中使事情正常工作更好,出于这些原因? - Nope
@FrançoisWahl 这实际上是个好建议。我只是更喜欢 Cr 和 FF,因为我觉得这些工具更好用。但我将不得不更仔细地在 IE 中检查一些东西。(好吧,我的专职测试人员将不得不这样做,呵呵。) - Konrad Viltersten
4个回答

21

基本上,document.querySelectorAll会返回一个类似数组的对象,而不是一个数组,我们需要在使用数组方法之前将其转换为数组。

var menus = document.querySelectorAll("ul.application>li>a");
menus = [].slice.call(menus);
menus.forEach(function(element) { ... });
如果您的环境支持ES6,那么您可以使用Array.from()
var menus = document.querySelectorAll("ul.application>li>a");
menus = Array.from(menus);
menus.forEach(function(element) { ... });

Array.from(menus)Array.apply(null,menus) 有何关联?我已经理解了文档中描述的概念,但是我看到两位声誉良好的用户给出了不同的建议,我想知道这些建议的区别。它们中的一个即将过时吗?更常用吗? - Konrad Viltersten
@KonradViltersten 两者都可以使用。Array.from是ES6中引入的专用函数,旨在避免将可迭代对象转换为数组时出现困难。一些可迭代对象的示例包括stringarguments等。另一方面,如果您的环境不支持ES6,则Array.apply(只是一种转换方式。在ES5中有很多转换方式。为了将所有方法汇集到一个单一的连接点,他们引入了Array.from - Rajaprabhu Aravindasamy

4
这不是浏览器的问题,更像是您获得了一个类似于数组对象的东西,通过 querySelectorAll。它会返回一个可迭代的NodeList,但不能直接使用数组方法。
但是您可以借用 Array.prototype 的方法,例如:
Array.prototype.forEach.call(menu, function(element) { /* ... */ });

如果您想首先获得一个真正的数组,可以使用以下方法进行转换:
array = Array.apply(null, menu);

你说得太对了!这正是IE控制台中所说的。我以为那只是一种滑稽的方式告诉我同样的事情。我的无知成了问题。现在,为什么它在FF和Cr中能够工作?他们有内置的魔法翻译吗? - Konrad Viltersten
他们扩展了这种语言。 - Nina Scholz
Array.from(menus)Array.apply(null,menus) 有什么关系?我理解文档中描述的概念,但是我看到两个声誉良好的用户提出了不同的建议,我想知道为什么会有不同的建议。它们中的一个即将过时吗?哪个更常用? - Konrad Viltersten
Array.from 是 ES6 中的新功能,根据兼容性列表,它不支持 IE。这意味着 Array.from 对你来说不是一个选项。 - Nina Scholz

4

可能有人遇到类似问题,不想或无法将所有forEach方法替换为[].forEach.call(elements, fn(el))。这里提供了适用于ie11的polyfill。

if (! Object.getOwnPropertyDescriptor(NodeList.prototype, 'forEach')) {
    Object.defineProperty(NodeList.prototype, 'forEach', Object.getOwnPropertyDescriptor(Array.prototype, 'forEach'));
}

1
最好的解决方案是在开头添加一行代码:
window.NodeList && !NodeList.prototype.forEach && (NodeList.prototype.forEach = Array.prototype.forEach) // make IE support forEach

之后,您可以像在其他正常浏览器中一样在IE中使用forEach。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接