“对象不支持此属性或方法” IE10/11

Tom*_*Tom 1 javascript internet-explorer

随着 ES6 的出现,我渴望放弃 jQuery 并在我的网站构建中使用原生 JS,以保持它们的快速和轻量。也是为了提高我的 JS 技能,因为我是直接使用 jQuery 的人之一。

我正在构建一个很小的库,以便在函数中使用更常用的 javascript 以保持文件较小。

function $(elm) {
    var elm = document.querySelectorAll(elm);

    this.forEach = function(f) {
        [].forEach.call(elm, f);
    }

    return elm;
}

function slider() {
    $(".slider").forEach(function() {
        alert("Hello");
    });
}
slider();
Run Code Online (Sandbox Code Playgroud)

这在 Chrome 等中效果很好。但在 IE10/11 中我收到错误

对象不支持此属性或方法“forEach”

指的是 $(".slider").forEach

有任何想法吗?

T.J*_*der 5

您添加forEach的是window对象,而不是您返回的对象;你$作为一个函数调用,而不是一个构造函数。由于您使用的是松散模式(显然),因此this在函数调用中是对全局对象的引用(也可以window在浏览器上访问)。您将querySelectorAll原封不动地返回集合。

它在 Chrome 上工作的原因是返回的集合querySelectorAll有自己的forEach(这是一个相当新的添加)。

为此,有四个选项:

  1. 返回一个对象并添加forEach到其中,将元素从 QSA 集合复制到该对象。例如:

    function $(selector) {
        const result = Array.from(document.querySelectorAll(selector));
        result.forEach = Array.prototype.forEach;
        // Perhaps map, filter, etc.; add in a loop?
        return result;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    或者在 ES5 中:

    var $ = (function() {
        var methods = Array.prototype;
        function $(selector) {
            var result = methods.slice.call(document.querySelectorAll(selector));
            result.forEach = methods.forEach;
            // Perhaps map, filter, etc.; add in a loop?
            return result;
        }
        return $;
    })();
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果原型不存在,则添加forEachNodeList原型中,并forEach直接在querySelectorAll. 例如:

    if (typeof NodeList !== "undefined" &&
        NodeList.prototype &&
        !NodeList.prototype.forEach) {
        // Yes, direct assignment is fine here, no need for `Object.defineProperty`
        NodeList.prototype.forEach = Array.prototype.forEach;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    (无需Object.defineProperty以上,enumerable[出奇] configurable,并且writabletrue为它在Chrome和Firefox,所以我们可以做直接分配同上。)

    ...然后当然你$就变成了

    function $(selector) {
        return document.querySelectorAll(selector);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    (首先。如果您想添加更多功能,您可能想要走#1 的方式。)

  3. 返回一个数组:

    function $(selector) {
        return Array.from(document.querySelectorAll(selector));
    }
    
    Run Code Online (Sandbox Code Playgroud)

    或者在 ES5 中:

    function $(selector) {
        return Array.prototype.slice.call(document.querySelectorAll(selector));
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 子类Array(在 ES2015 之前的 JavaScript 引擎上无法完美填充),因此您可以在 的功能之上添加自己Array的功能:

    class MyThingy extends Array {
        // Perhaps further methods here
    }
    function $(selector) {
        return MyThingy.from(document.querySelectorAll(selector));
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这里没有 ES5 选项,您至少需要转译和 polyfill。

如果您要添加超出Array. 它可能足以满足您的目的。