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

IT技术 javascript internet-explorer
2021-01-12 13:15:38

随着 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();

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

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

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

有任何想法吗?

1个回答

您添加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;
    }
    

    或者在 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 $;
    })();
    
  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;
    }
    

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

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

    function $(selector) {
        return document.querySelectorAll(selector);
    }
    

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

  3. 返回一个数组:

    function $(selector) {
        return Array.from(document.querySelectorAll(selector));
    }
    

    或者在 ES5 中:

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

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

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

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

我想我想至少支持 IE11。我应该看哪个 polyfill?
2021-03-18 13:15:38
@Tom:我为上面的 1-3 添加了 ES5 选项。重新编译和填充,我对Babel很满意你可以直接转译(这意味着不使用类似的东西Array.from),或者同时转译和 polyfill;网站上的详细信息。
2021-03-22 13:15:38
@Tom:如果您正在为 IE10 编写代码,则需要将自己转译或限制为 ES5 语法。我从你的开场白中假设你正在使用 ES2015+(必要时进行转译和 polyfill)。
2021-04-08 13:15:38
1. 看起来是个不错的方法,但是在IE10下不行,使用const会出现语法错误,使用var give object不支持方法"from"
2021-04-10 13:15:38