Javascript Safari 和 IE 中的 ES6 TypeError

Javascript ES6 TypeError in Safari & IE

我正在使用 Javascript 由其他人在 Wordpress 站点中使用 ES6 编写的代码。它进行 Ajax 调用以在 DOM 中显示数据,这适用于 Chrome 和 Firefox 但由于某种原因 Safari 在控制台中给出以下错误:

TypeError: document.querySelectorAll(".js_zip-lookup__submit").forEach is not a function. (In 'document.querySelectorAll(".js_zip-lookup__submit").forEach(function(e){e.addEventListener("click",function(){displayResults(e.parentNode.querySelector(".zip-lookup__input").value)})})', 'document.querySelectorAll(".js_zip-lookup__submit").forEach' is undefined)

这是函数:

function finderInit(){
  document.querySelectorAll('.js_zip-lookup__submit').forEach(function(button){
    button.addEventListener('click', function(){
      const zip = button.parentNode.querySelector('.zip-lookup__input').value;
      displayResults(zip);
    });
  });

  document.querySelectorAll('.zip-lookup').forEach(function(form){
    form.addEventListener('submit', function(e){
      e.preventDefault();
      const zip = form.querySelector('.zip-lookup__input').value;
      displayResults(zip);
    })
  });
}

而且我不太清楚为什么 Safari 会对此有问题,而 Chrome/FF 甚至没有在控制台中记录有关此特定部分的任何错误并且它工作得很好。我知道这应该是一些浏览器兼容性问题,但到目前为止还没有找到太多信息。

document.querySelectorAll returns NodeList 对象,不是数组。因为它 can be seen on MDNNodeListforEach 方法但它没有得到很好的支持,这就是为什么它在最近的 Firefox 和 Chrome 中工作但在其他浏览器(Safari)中不工作的原因:

Although NodeList is not an Array, it is possible to iterate on it using forEach(). Several older browsers have not implemented this method yet.

要以兼容的方式遍历节点列表和其他迭代器,应该使用 Array.from(可以在旧浏览器中填充):

Array.from(document.querySelectorAll(".js_zip-lookup__submit")).forEach(...);

如@Estus 所述,旧版本的 Safari 不会在 nodelist 对象上实现 .forEach。但是,Array.prototype.forEachES5.1 规范中被定义为通用的:

The forEach function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the forEach function can be applied successfully to a host object is implementation-dependent.

因此,一个可行的解决方案是在节点列表上调用 Array.prototype.forEach 并将您要执行的函数传递给它。作为一个精简(且便宜)的测试用例:

var col = document.getElementsByTagName("p");
//col.forEach(                    function (el) {document.write(el.id)});
Array.prototype.forEach.call(col, function (el) {document.write(el.id)});
<p id="p1"></p>
<p id="p2"></p>
<p id="p3"></p>
<p id="p4"></p>

这已经过测试,发现可以在 Windows 的 Safari 5.1.7 和 Internet 下使用。 Explorer 9 仿真。注释掉的行重现了 Safarai 5.1.7.post 中报告的错误。

我尝试了 Array.prototype 的多种变体,但唯一解决 IE 和 Safari 兼容性问题的方法是包含下面的这个 polypill 代码段,解决方案在 this blog 中找到:

(function () {
    if ( typeof NodeList.prototype.forEach === "function" ) return false;
    NodeList.prototype.forEach = Array.prototype.forEach;
})();