在 IE 中向 Array.prototype 添加函数会导致它作为元素被推入每个数组

Adding a function to Array.prototype in IE results in it being pushed in to every array as an element

我在我的项目开始时向 Array 添加了以下 polyfill:

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 中被 pushed 作为一个元素它,我什至可以像这样访问它:

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

这会在 IE 中抛出各种异常,其中包含 .forEach 等函数,我希望得到一些数据,但已找到此函数。

这是 IE 开发者工具的截图,在这种情况下,这个数组应该只有 2 个元素,而不是 3 个。

从 Chrome 开始,这就是应该的样子。事实上,我相信即使实际内容是错误的,但我还没有到达那里(它应该是一个包含长度为2的数组的数组)。

为什么 JavaScript 在 IE11 中仍然表现得如此错误,我怎样才能正确地将此函数添加到 prototype 而不是在每个 Array 实例中?

并不是每个数组都 "pushed";您向原型对象添加了一个 属性,因此它在每个数组实例中都是 visibleenumerable。这就是原型属性应该如何工作。

它在 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;
    }
  });
}

除了属性"value",明明是新的属性的值,属性"enumerable"和"configurable"默认为false。这意味着 "find" 不会出现在涉及遍历对象属性的任何情况下。