【问题标题】:Alternative or polyfill for Array.from on the Internet ExplorerInternet Explorer 上 Array.from 的替代或 polyfill
【发布时间】:2016-08-17 02:16:42
【问题描述】:

我在 Internet Explorer 上的 Angular 应用程序有问题。它在任何地方都可以正常运行(Chrome、Mozilla、Edge),但在 IE 上不能

我已经用开发者资源管理器分析了错误所在,它返回错误发生在以下行:

myDataSet[index - 1].data = Array.from(tmp);

我收到以下错误消息:

对象不支持匿名函数中的属性或方法......(等)

我在那里做的是我有一个名为tmpSet(),其中包含以下数据:

之后我只是从这个Set 创建一个简单的数组对象。

我该如何解决这个问题?

编辑

根据建议,我在我的应用中添加了以下代码:

if (!Array.from) {
  Array.from = (function () {
    var toStr = Object.prototype.toString;
    var isCallable = function (fn) {
      return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
    };
    var toInteger = function (value) {
      var number = Number(value);
      if (isNaN(number)) { return 0; }
      if (number === 0 || !isFinite(number)) { return number; }
      return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
    };
    var maxSafeInteger = Math.pow(2, 53) - 1;
    var toLength = function (value) {
      var len = toInteger(value);
      return Math.min(Math.max(len, 0), maxSafeInteger);
    };

    // The length property of the from method is 1.
    return function from(arrayLike/*, mapFn, thisArg */) {
      // 1. Let C be the this value.
      var C = this;

      // 2. Let items be ToObject(arrayLike).
      var items = Object(arrayLike);

      // 3. ReturnIfAbrupt(items).
      if (arrayLike == null) {
        throw new TypeError("Array.from requires an array-like object - not null or undefined");
      }

      // 4. If mapfn is undefined, then let mapping be false.
      var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
      var T;
      if (typeof mapFn !== 'undefined') {
        // 5. else
        // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
        if (!isCallable(mapFn)) {
          throw new TypeError('Array.from: when provided, the second argument must be a function');
        }

        // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
        if (arguments.length > 2) {
          T = arguments[2];
        }
      }

      // 10. Let lenValue be Get(items, "length").
      // 11. Let len be ToLength(lenValue).
      var len = toLength(items.length);

      // 13. If IsConstructor(C) is true, then
      // 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
      // 14. a. Else, Let A be ArrayCreate(len).
      var A = isCallable(C) ? Object(new C(len)) : new Array(len);

      // 16. Let k be 0.
      var k = 0;
      // 17. Repeat, while k < len… (also steps a - h)
      var kValue;
      while (k < len) {
        kValue = items[k];
        if (mapFn) {
          A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
        } else {
          A[k] = kValue;
        }
        k += 1;
      }
      // 18. Let putStatus be Put(A, "length", len, true).
      A.length = len;
      // 20. Return A.
      return A;
    };
  }());
}

【问题讨论】:

    标签: javascript arrays internet-explorer set


    【解决方案1】:

    Array.from 在以下文档模式中不受支持:Quirks、Internet Explorer 6 标准、Internet Explorer 7 标准、Internet Explorer 8 标准、Internet Explorer 9 标准、Internet Explorer 10 标准、Internet Explorer 11 标准。 Windows 8.1 不支持 (compatibility reference)

    只需将以下代码添加到您的页面 (JS code was copied from developer.mozilla.org)。它将模拟 ES6 的 Array.from 方法。

    Array.from 在第 6 版中被添加到 ECMA-262 标准中;作为 因此它可能不会出现在该标准的其他实现中。 您可以通过在 脚本的开头,允许使用 Array.from in 本身不支持它的实现。这个算法是 与 ECMA-262 第 6 版中指定的完全相同,假设为 Object 和 TypeError 有它们的原始值和那个 callback.call 计算为 Function.prototype.call 的原始值。在 此外,由于真正的可迭代对象不能被填充,因此 实现不支持定义在 ECMA-262 第 6 版。

    if (!Array.from) {
      Array.from = (function () {
        var toStr = Object.prototype.toString;
        var isCallable = function (fn) {
          return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
        };
        var toInteger = function (value) {
          var number = Number(value);
          if (isNaN(number)) { return 0; }
          if (number === 0 || !isFinite(number)) { return number; }
          return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
        };
        var maxSafeInteger = Math.pow(2, 53) - 1;
        var toLength = function (value) {
          var len = toInteger(value);
          return Math.min(Math.max(len, 0), maxSafeInteger);
        };
    
        // The length property of the from method is 1.
        return function from(arrayLike/*, mapFn, thisArg */) {
          // 1. Let C be the this value.
          var C = this;
    
          // 2. Let items be ToObject(arrayLike).
          var items = Object(arrayLike);
    
          // 3. ReturnIfAbrupt(items).
          if (arrayLike == null) {
            throw new TypeError("Array.from requires an array-like object - not null or undefined");
          }
    
          // 4. If mapfn is undefined, then let mapping be false.
          var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
          var T;
          if (typeof mapFn !== 'undefined') {
            // 5. else
            // 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
            if (!isCallable(mapFn)) {
              throw new TypeError('Array.from: when provided, the second argument must be a function');
            }
    
            // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
            if (arguments.length > 2) {
              T = arguments[2];
            }
          }
    
          // 10. Let lenValue be Get(items, "length").
          // 11. Let len be ToLength(lenValue).
          var len = toLength(items.length);
    
          // 13. If IsConstructor(C) is true, then
          // 13. a. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
          // 14. a. Else, Let A be ArrayCreate(len).
          var A = isCallable(C) ? Object(new C(len)) : new Array(len);
    
          // 16. Let k be 0.
          var k = 0;
          // 17. Repeat, while k < len… (also steps a - h)
          var kValue;
          while (k < len) {
            kValue = items[k];
            if (mapFn) {
              A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
            } else {
              A[k] = kValue;
            }
            k += 1;
          }
          // 18. Let putStatus be Put(A, "length", len, true).
          A.length = len;
          // 20. Return A.
          return A;
        };
      }());
    }
    

    【讨论】:

    • 感谢您的解释。你能告诉我用什么代码代替我的Array.from,好吗?
    • 我已经更新了我的答案。只需将 JavaScript 代码复制到您的页面中即可。例如到主 JS 文件。你的问题就会迎刃而解!
    • 你可以试试myDataSet[index - 1].data = Array.prototype.slice.call(tmp);
    • 这根本不能解决 IE 中的问题。
    • 在添加您的代码并在 Internet Explorer 11 中检查后出现错误。此站点使用不支持迭代的实现覆盖 Array.from(),这可能导致 Google Maps JavaScript API v3无法正常工作。
    【解决方案2】:

    我遇到了同样的问题。看着 polyfill,它的威胁很大。这是 2 行简短的解决方案。

    OP 基本上需要从他的类数组对象创建简单的数组。我习惯了最有效的 2 行纯 for 循环(我必须从 HTML DOM 节点列表类数组对象创建数组,同样适用于 JavaScript arguments 对象)。

    对于 OP 来说,听起来可能是这样的:

    var temp_array = [],
        length = tmp.length;
    
    for (var i = 0; i < length; i++) {
        temp_array.push(tmp[i]);
    }
    
    // Here you get the normal array "temp_array" containing all items
    // from your `tmp` Set.
    

    使其成为独立的功能,您将获得适用于 IE

    下面是单独的函数的样子:

    /**
     * @param arr The array | array-like data structure.
     * @param callback The function to process each element in the 'arr'.
     * The callback signature and usage is assumed similar to the 
     * native JS 'forEach' callback argument usage.
     */
    function customEach(arr, callback) {
        'use strict';
        var l = arr.length;
        for (var i = 0; i < l; i++) {
            callback(arr[i], i, arr);
        }
    };
    

    PS:这里是forEach callback的相关描述,看看如何使用customEach回调。

    【讨论】:

      【解决方案3】:

      虽然 IE 不支持它,但您可以使用 MDN 中的 polyfill

      【讨论】:

        【解决方案4】:

        您可以将slice.call 用于类似数组的对象。这意味着您的代码将显示为:

        myDataSet[index - 1].data = [].slice.call(tmp);

        【讨论】:

        • 一个像魅力一样工作的衬里。甚至可以在 IE 中使用
        【解决方案5】:

        这里和 MDN 的第一个正确答案

        问题的原始海报写道:

        我在那里做的是我有一个名为tmpSet() ...

        但是我们在这里有 3 个答案已经 4 年多了,没有人Set 对象对其进行测试。
        huge polyfill from MDN 不适用于 Set 对象!

        它是从 MDN 复制并粘贴到接受的答案中,未经测试。

        我的 polyfill 解决方案也比来自 MDN 的不正确和巨大的 polyfill 短得多。

        在以下解决方案中,您将在 cmets 中找到有关函数及其参数的说明。

        /**
         * @param "arr" (required) - array-like or iterable object to convert it to an array.
         * @param "callbackFn" (optional) - function to call on every element of the array.
         * @param "thisArg" (optional) - value to use as this when executing callback
         * Return value - new Array instance
         *
         * The callbackFn argument usage is like in Array.map() callback.
         * The callbackFn function accepts the following arguments:
         *      @param "currentValue" (required) - the current element being processed in the array.
         *      @param "index" (optional) - the index of the current element being processed in the array.
         *      @param "array" (optional) - he array map was called upon.
         * Callback function that is called for every element of "arr". Each time callback executes, the returned value is added to new array ("arNew").
         */
        function arrayFrom(arr, callbackFn, thisArg)
        {
            //if you need you can uncomment the following line
            //if(!arr || typeof arr == 'function')throw new Error('This function requires an array-like object - not null, undefined or a function');
        
            var arNew = [],
                k = [], // used for convert Set to an Array
                i = 0;
        
            //if you do not need a Set object support then
            //you can comment or delete the following if statement
            if(window.Set && arr instanceof Set)
            {
                //we use forEach from Set object
                arr.forEach(function(v){k.push(v)});
                arr = k
            }
        
            for(; i < arr.length; i++)
                arNew[i] = callbackFn
                    ? callbackFn.call(thisArg, arr[i], i, arr)
                    : arr[i];
        
            return arNew
        }
        
        //You could also use it without the following line, but it is not recommended because native function is faster.
        Array.from = Array.from || arrayFrom; //We set it as polyfill
        
        //HOW TO USE IT:
        
        function myCallback1(x){return x+x}
        
        function myCallback2(o){return o.innerHTML}
        
        var str = 'Super!',
            array = str.split(''),//['S','u','p','e','r','!']
            arrayLike1 = window.Set ? new Set(str) : array, //array for IE < 10. Only 11 version of IE supports Set.
            arrayLike2 = document.querySelectorAll('b');//NodeList
            arrayLike3 = document.getElementsByTagName('b');//HTMLCollection
        
        console.log(arrayFrom(str).join(','));//S,u,p,e,r,!
        console.log(arrayFrom(array).join(','));//S,u,p,e,r,!
        console.log(arrayFrom(str, myCallback1).join(','));//SS,uu,pp,ee,rr,!!
        console.log(arrayFrom(arrayLike1, myCallback1).join(','));//SS,uu,pp,ee,rr,!!
        console.log(arrayFrom(arrayLike2, myCallback2).join(','));//aaa,bbb
        console.log(arrayFrom(arrayLike3, myCallback2).join(','));//aaa,bbb
        //You can also use it as polyfill:
        console.log(Array.from(str).join(','));//S,u,p,e,r,!
        &lt;b&gt;aaa&lt;/b&gt; &lt;b&gt;bbb&lt;/b&gt;

        不要忘记Set 具有唯一值!例如:

        //Only 11 version of IE and all modern browsers support Set.
        var ar = [];
        new Set('mama').forEach(function(v){ar.push(v)});
        console.log(ar.join(',')); // 'm','a'

        【讨论】:

          猜你喜欢
          • 2020-11-22
          • 1970-01-01
          • 2018-02-01
          • 2010-10-12
          • 2010-12-14
          • 1970-01-01
          • 2014-10-15
          • 2020-10-02
          • 1970-01-01
          相关资源
          最近更新 更多