有人能解释一下这个Array.prototype.find()的polyfill吗?

8
这个MDN页面[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find]上有一个polyfill:
if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    enumerable: false,
    configurable: true,
    writable: true,
    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++) {
        if (i in list) {
          value = list[i];
          if (predicate.call(thisArg, value, i, list)) {
            return value;
          }
        }
      }
      return undefined;
    }
  });
}

我的问题是这些行是用来做什么的:
var list = Object(this);
var length = list.length >>> 0;

由于这绝对是一个数组(我们正在增强Array.prototype),所以为什么要确保length是数字,为什么要使用Object()?


2
这个 polyfill 的问题在于它需要 Object.defineProperty 方法,而旧浏览器中没有实现 find 方法。 - kennebec
正如答案所示,“this”不能保证是一个数组,您可以在以下答案中看到“this”可能是什么(如果您需要比T.J.提供的更多信息):https://dev59.com/J2Qo5IYBdhLWcg3wbe5K#16063711(在“the this variable”下)。 - HMR
1个回答

12
基本答案是polyfill只是忠实地实现了ES6草案规范中算法的第1步和第4步(截至5月22日草案的§22.1.3.8)。 (其中ToLength基本上是转换为数字。)由于现在可以使用非对象值作为this(通过Function#call和Function#apply,或者直接在严格模式下调用函数),因此步骤1是有意义的。但我们不知道this是否为数组。请参见当前ES6草案规范中的此注释:find函数有意是通用的;它不需要其this值是Array对象。因此,它可以被传输到其他类型的对象以用作方法。 find函数能否成功应用于不是Array的奇异对象取决于实现。您会发现将该注释添加到分配给原型的几乎所有预定义函数上。例如,您可以通过将它们分配给对象或其他原型直接使用它们进行其他操作。
MyNiftyThing.prototype.find = Array.prototype.find;

...或通过Function#callFunction#apply来调用。

所以假设我想在一个arguments对象上使用Array#findarguments当然是类似数组但不是一个数组。所以我可以这样做:

function foo() {
    var firstObject = Array.prototype.find.call(arguments, function(val) {
        return typeof val === "object";
    });
    // ...
}

另一个更为著名的例子(不涉及find)是使用slice将类数组对象转换为数组:

function foo() {
    // Turn the `arguments` pseudo-array into a real array
    var args = Array.prototype.slice.call(arguments, 0);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接