【问题标题】:Adding a function to Array.prototype in IE results in it being pushed in to every array as an element在 IE 中向 Array.prototype 添加一个函数会导致它作为一个元素被推入每个数组
【发布时间】:2016-09-27 19:13:22
【问题描述】:

我在项目开始时将以下 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 个。

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

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

【问题讨论】:

    标签: javascript internet-explorer-11


    【解决方案1】:

    它并没有被“推入”每个数组;您向原型对象添加了一个属性,因此它在每个数组实例中都是 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。这意味着在涉及遍历对象属性的任何情况下都不会出现“查找”。

    【讨论】:

    • 这是一个很好的答案,而且有效!最后一个问题,我从 Mozilla 开发者网络 (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…) 获取了这个 polyfill,他们所有的 polyfill 都使用相同的方法直接将函数添加到对象的原型中(另一个示例:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…)。我应该完全避免它并始终使用defineProperty吗?或者这只是Array 中的一个问题?
    • 就我个人而言,我会使用defineProperty(),但如果你试图让事情在 IE8 或更早版本上运行,你会遇到困难。如果defineProperty 不起作用,您总是可以退回到简单地将属性添加到原型中。
    • @WillP。是的,在 IE9 之前无法修改 IE 中的原生原型。
    • 刚刚重新阅读您之前的评论并意识到我是多余的:P
    • MDN 表示 enumerable 默认为 false。因此,我认为这是 IE11 中的错误。
    猜你喜欢
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多