Добавление функции в Array.prototype в IE приводит к тому, что она вставляется в каждый массив как элемент

Я добавил следующий polyfill в Array в начале моего проекта:

if (!Array.prototype.find) {
  Array.prototype.find = function(predicate) {
    if (this === null) {
      throw new TypeError('Array.prototype.find called on null or undefined');
    }
    if (typeof predicate !== 'function') {
      throw new TypeError('predicate must be a function');
    }
    var list = Object(this);
    var length = list.length >>> 0;
    var thisArg = arguments[1];
    var value;

    for (var i = 0; i < length; i++) {
      value = list[i];
      if (predicate.call(thisArg, value, i, list)) {
        return value;
      }
    }
    return undefined;
  };
}

Это прекрасно работает в Chrome и Firefox, но в Internet Explorer 11 эта функция на самом деле нажата в каждом Array как элемент, и я могу даже получить к ней доступ, как:

var a = [];
a[0]();

Это бросает всевозможные исключения в IE с такими функциями, как .forEach, где я ожидаю некоторые данные, и эта функция найдена.

Вот скриншот из инструментов разработчика IE, в этом случае этот массив должен иметь всего 2 элемента вместо 3.

IE - неправильный

И так должно быть, из Chrome. На самом деле, я считаю, что даже фактическое содержимое неверно, но я еще не получил его (это должен быть массив, содержащий массивы длиной 2).

Chrome - правильный

Как JavaScript может вести себя так неправильно в IE11, и как я могу правильно добавить эту функцию в prototype вместо каждого экземпляра Array?

Ответы

Ответ 1

Это не "толкается" в каждый массив; вы добавили свойство объекта-прототипа, чтобы оно было видимым и перечислимым в каждом экземпляре массива. То, как должны работать прототипы.

Он работает в Chrome и Firefox, потому что .find() в прототипе в этих средах определяется таким образом, чтобы быть видимым, но не перечислимым. Вы можете сделать это в IE с помощью Object.defineProperty():

if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, "find", {
    value: function(predicate) {
      if (this === null) {
        throw new TypeError('Array.prototype.find called on null or undefined');
      }
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }
      var list = Object(this);
      var length = list.length >>> 0;
      var thisArg = arguments[1];
      var value;

      for (var i = 0; i < length; i++) {
        value = list[i];
        if (predicate.call(thisArg, value, i, list)) {
          return value;
        }
      }
      return undefined;
    }
  });
}

Помимо свойства "значение", которое явно является значением нового свойства, свойства "перечислимые" и "настраиваемые" по умолчанию равны false. Это означает, что "find" не будет отображаться в любой ситуации, которая включает итерацию через свойства объекта.