简体   繁体   English

如何为 IE8 填充 Array.prototype.includes()

[英]How to Polyfill Array.prototype.includes() for IE8

I'm trying to polyfill the array method includes() to work with IE8, which I need to support for a project and I don't want to use indexOf().我正在尝试填充数组方法 includes() 以与 IE8 一起使用,我需要支持一个项目并且我不想使用 indexOf()。

I know there's a polyfill, so I went to:我知道有一个 polyfill,所以我去了:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes#Polyfill https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes#Polyfill

And included it at the top of my script.并将其包含在我的脚本顶部。

IE8 has limited support for Object.defineProperty() so I polyfilled it as well: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties#Polyfill IE8 对 Object.defineProperty() 的支持有限,所以我也对它进行了 polyfill: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties#Polyfill

Lastly, I needed to polyfill Object.keys(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys#Polyfill最后,我需要 polyfill Object.keys(): https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys#Polyfill

Put together, my polyfills are:放在一起,我的 polyfills 是:

if (!Object.keys) {
  Object.keys = (function() {
    'use strict';
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
        dontEnums = [
          'toString',
          'toLocaleString',
          'valueOf',
          'hasOwnProperty',
          'isPrototypeOf',
          'propertyIsEnumerable',
          'constructor'
        ],
        dontEnumsLength = dontEnums.length;

    return function(obj) {
      if (typeof obj !== 'function' && (typeof obj !== 'object' || obj === null)) {
        throw new TypeError('Object.keys called on non-object');
      }

      var result = [], prop, i;

      for (prop in obj) {
        if (hasOwnProperty.call(obj, prop)) {
          result.push(prop);
        }
      }

      if (hasDontEnumBug) {
        for (i = 0; i < dontEnumsLength; i++) {
          if (hasOwnProperty.call(obj, dontEnums[i])) {
            result.push(dontEnums[i]);
          }
        }
      }
      return result;
    };
  }());
}

function defineProperties(obj, properties) {
  function convertToDescriptor(desc) {
    function hasProperty(obj, prop) {
      return Object.prototype.hasOwnProperty.call(obj, prop);
    }

    function isCallable(v) {
      // NB: modify as necessary if other values than functions are callable.
      return typeof v === 'function';
    }

    if (typeof desc !== 'object' || desc === null)
      throw new TypeError('bad desc');

    var d = {};

    if (hasProperty(desc, 'enumerable'))
      d.enumerable = !!desc.enumerable;
    if (hasProperty(desc, 'configurable'))
      d.configurable = !!desc.configurable;
    if (hasProperty(desc, 'value'))
      d.value = desc.value;
    if (hasProperty(desc, 'writable'))
      d.writable = !!desc.writable;
    if (hasProperty(desc, 'get')) {
      var g = desc.get;

      if (!isCallable(g) && typeof g !== 'undefined')
        throw new TypeError('bad get');
      d.get = g;
    }
    if (hasProperty(desc, 'set')) {
      var s = desc.set;
      if (!isCallable(s) && typeof s !== 'undefined')
        throw new TypeError('bad set');
      d.set = s;
    }

    if (('get' in d || 'set' in d) && ('value' in d || 'writable' in d))
      throw new TypeError('identity-confused descriptor');

    return d;
  }

  if (typeof obj !== 'object' || obj === null)
    throw new TypeError('bad obj');

  properties = Object(properties);

  var keys = Object.keys(properties);
  var descs = [];

  for (var i = 0; i < keys.length; i++)
    descs.push([keys[i], convertToDescriptor(properties[keys[i]])]);

  for (var i = 0; i < descs.length; i++)
    Object.defineProperty(obj, descs[i][0], descs[i][1]);

  return obj;
}

if (!Array.prototype.includes) {
alert('test');

  defineProperties(Array.prototype, 'includes', {
    value: function(searchElement, fromIndex) {
                'use strict';

      if (this === null) {
        throw new TypeError('"this" is null or not defined');
      }

      // 1. Let O be ? ToObject(this value).
      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If len is 0, return false.
      if (len === 0) {
        return false;
      }

      // 4. Let n be ? ToInteger(fromIndex).
      //    (If fromIndex is undefined, this step produces the value 0.)
      var n = fromIndex | 0;

      // 5. If n ≥ 0, then
      //  a. Let k be n.
      // 6. Else n < 0,
      //  a. Let k be len + n.
      //  b. If k < 0, let k be 0.
      var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);

      function sameValueZero(x, y) {
        return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
      }

      // 7. Repeat, while k < len
      while (k < len) {
        // a. Let elementK be the result of ? Get(O, ! ToString(k)).
        // b. If SameValueZero(searchElement, elementK) is true, return true.
        if (sameValueZero(o[k], searchElement)) {
          return true;
        }
        // c. Increase k by 1. 
        k++;
      }

      // 8. Return false
      return false;
    }
  });
}

To test the above script, I did:为了测试上面的脚本,我做了:

var arr = ["one", "two", "three"];

alert( arr.includes('two') );

IE8 throws this error: IE8 抛出此错误:

Object doesn't support this property or method.

I thought that by using polyfills, I would be able to add support for array includes() to IE8.我认为通过使用 polyfills,我可以向 IE8 添加对数组 includes() 的支持。 What am I doing wrong?我究竟做错了什么? Any corrections or links to other polyfills are welcomed.欢迎任何更正或指向其他 polyfill 的链接。 No jQuery or other libraries.没有 jQuery 或其他库。 I just want to add support for includes() to IE.我只想为 IE 添加对 includes() 的支持。

You can simply use Array#indexOf to polyfill Array#includes .您可以简单地使用Array#indexOf来填充Array#includes

For IE8, you will also need to polyfill Array#indexOf as it was only implemented in IE9.对于 IE8,您还需要对Array#indexOf因为它仅在 IE9 中实现。

if(!Array.prototype.includes){
   //or use Object.defineProperty
   Array.prototype.includes = function(search){
    return !!~this.indexOf(search);
  }
}
if(!Array.prototype.indexOf){
Array.prototype.indexOf = (function(Object, max, min){
  "use strict";
  return function indexOf(member, fromIndex) {
    if(this===null||this===undefined)throw TypeError("Array.prototype.indexOf called on null or undefined");

    var that = Object(this), Len = that.length >>> 0, i = min(fromIndex | 0, Len);
    if (i < 0) i = max(0, Len+i); else if (i >= Len) return -1;

    if(member===void 0){ for(; i !== Len; ++i) if(that[i]===void 0 && i in that) return i; // undefined
    }else if(member !== member){   for(; i !== Len; ++i) if(that[i] !== that[i]) return i; // NaN
    }else                           for(; i !== Len; ++i) if(that[i] === member) return i; // all else

    return -1; // if the value was not found, then return -1
  };
})(Object, Math.max, Math.min);
}

 Array.prototype.includes = null; Array.prototype.indexOf = null; if(!Array.prototype.includes){ console.log('Polyfilled Array.prototype.includes'); //or use Object.defineProperty Array.prototype.includes = function(search){ return !!~this.indexOf(search); } } if(!Array.prototype.indexOf){ console.log("Polyfilled Array.prototype.indexOf"); Array.prototype.indexOf = (function(Object, max, min){ "use strict"; return function indexOf(member, fromIndex) { if(this===null||this===undefined)throw TypeError("Array.prototype.indexOf called on null or undefined"); var that = Object(this), Len = that.length >>> 0, i = min(fromIndex | 0, Len); if (i < 0) i = max(0, Len+i); else if (i >= Len) return -1; if(member===void 0){ for(; i !== Len; ++i) if(that[i]===void 0 && i in that) return i; // undefined }else if(member !== member){ for(; i !== Len; ++i) if(that[i] !== that[i]) return i; // NaN }else for(; i !== Len; ++i) if(that[i] === member) return i; // all else return -1; // if the value was not found, then return -1 }; })(Object, Math.max, Math.min); } var obj = {x: 1, y: 2}; var arr = [1, 'what', obj]; console.log('Array includes 1:',arr.includes(1)); console.log('Array includes \\'what\\':', arr.includes('what')); console.log('Array includes obj:', arr.includes(obj)); console.log('Array includes 3:', arr.includes(3));

use arr.indexOf('two')使用 arr.indexOf('two')

if return 1 is because it exists, and -1 does not exist如果返回1是因为它存在,而-1不存在

Unfortunately I don't have a way to test in IE8, but I think there are a couple of things going on here -- first, you don't need to define defineProperties(obj, properties) because neither the Object.keys nor Array.prototype.includes polyfills use it -- they are both self-contained.不幸的是,我没有办法在 IE8 中进行测试,但我认为这里有几件事情要做——首先,你不需要定义defineProperties(obj, properties)因为Object.keysArray.prototype.includes使用它——它们都是独立的。 The fact that they are self-contained also means that you don't need to include the Object.keys polyfill.它们是自包含的这一事实也意味着您不需要包含Object.keys polyfill。

I would suggest only using the includes Array.prototype.includes if that is all you need.如果这就是你所需要的,我建议只使用包含Array.prototype.includes

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM