数组 return `true` 中的未定义条目在使用 `every` 将它们解析为布尔值后

Undefined entries in an array return `true` after parsing them as boolean with `every`

为了跟踪 3 个布尔值,我决定使用一个简单的数组:

var processingDone = Array(3);

然后,我将布尔值设置为正确的索引(伪代码):

function stepTwoDone(){
    processingDone[1] = true;
}

我想出了一个简单的方法来检查是否所有的布尔值都为真,就是使用 every,像这样:

if(processingDone.every(Boolean)){
    // Do stuff
}

现在,由于某种原因,如果不是所有的布尔值都被设置,但是 设置的所有布尔值都是 trueevery returns true:

alert('Array(3): '     + Array(3).every(Boolean) + '\n' +         // true
      '[,,]: '         + [,,].every(Boolean) + '\n' +             // true
      '[true,,true]: ' + [true,,true].every(Boolean) + '\n' +     // true
      '[,false,]: '    + [,false,].every(Boolean) + '\n' +        // false
      'All true: '     + [true,true,true].every(Boolean) + '\n' + // true
      'All false: '    + [false,false,false].every(Boolean));     // false


那么,这是怎么回事?
为什么数组中的未定义值在传递给 Boolean 构造函数时看起来等于真值?只需调用 Boolean() 不带参数 returns false,如预期...


当然,简单的解决方案是首先将值设置为虚假值:

var processingDone = [false, false, false];

MDN forEach

forEach executes the provided callback once for each element present in the array in ascending order. It is not invoked for indexes that have been deleted or elided. However, it is executed for elements that are present and have the value undefined.

我强烈怀疑 every 也是这样循环的,尽管我正在搜索规范。

因此,当 [true,,true] 调用 every 时,只有 [true,true](比方说)被传递,因为第二个元素被忽略。但是请考虑以下

[true,undefined,true].every(Boolean) // false

上面的returnsfalse作为它实际上包含undefined,而不仅仅是undefined的结果这就是当我们尝试访问索引尚未设置的数组元素时得到的结果。

在我们的例子中,[true,,true] 在 0 和 2 索引中有值,但在 1

中没有

总结:

布尔值(或指定的回调)仅针对存在的实际值调用,而不针对导致 falsey 值 (undefined) 的值调用,因为它们不'首先存在。

ECMAScript Language Specification - ECMA-262 Edition 5.1 also suggests the same

这就是 array.every 的工作原理:

  • 为每个已赋值的数组元素调用回调,它不会为已删除或从未赋值的索引(例如您的 Array(3) )调用

  • 如果回调 return 为假值,它将 return 为假。因为您没有分配值,所以 Boolean 永远不会被调用。

试一试

[false,false,false].every(function(value) {
  console.info(arguments); 
  return true;
});

对比(无控制台输出)

Array(3).every(function(value) {
  console.info(arguments); 
  return true;
});