为什么map,every和其他数组函数会跳过空值?

时间:2019-08-07 12:37:51

标签: javascript

背景

我正在编写一些代码来检查2个数组是否相同,但是由于某种原因,当期望为false时结果为true。仔细检查后发现,未定义的数组值被跳过。

示例

const arr1 = [, , 3, 4]
const arr2 = [1, 2, 3, 4]
const result = arr1.every((item, index) => item === arr2[index])
console.log(result) // true (HOW????)

我尝试过的

所以我花了一些时间尝试正确地获取值,但我唯一想到的是一个常规的for循环,该循环基于数组长度而不是实际项进行迭代。

问题

为什么会发生这种情况,有没有办法识别我的数组中这些空/未定义的值?

4 个答案:

答案 0 :(得分:12)

这是对forEach仅访问实际存在的元素这一事实的扩展。我不知道有什么更深层的“为什么”,除了为缺少的元素调用回调没有多大意义。

您可以使用以下方法实现这些元素(如果就是世界):

  1. 扩展符号,或
  2. Array.from
  3. Array.prototype.values
  4. Array.prototype.entries

...或其他一些人。

const a = [, , 3];
console.log(a.hasOwnProperty(0)); // false
const b = [...a];
console.log(b.hasOwnProperty(0)); // true
const c = Array.from(a);
console.log(b.hasOwnProperty(0)); // true

通过Array.from将其应用于您的函数:

const arr1 = [, , 3, 4]
const arr2 = [1, 2, 3, 4]
const result = Array.from(arr1).every((item, index) => item === arr2[index])
console.log(result) // false

当然,这涉及到创建一个新数组并循环遍历上一个复制元素。使用自己的for循环可能会更好。

Array.prototype.entries应用于您的函数:

const arr1 = [, , 3, 4]
const arr2 = [1, 2, 3, 4]
let result = true;
for (const [index, value] of arr1.entries()) {
    if (value !== arr2[index]) {
        result = false;
        break;
    }
}
console.log(result) // false

答案 1 :(得分:3)

因为语言设计是如此。 ??‍♂️

请参见the specification,其中指出:

  
      
  • 重复,而k   
  • 让Pk为ToString(k)。
  •   
  • kPresent具有HasProperty (O,Pk)。
  •   
  • ReturnIfAbrupt(kPresent)。
  •   
  • 如果kPresent为true ,则
  •   
  

…然后进行操作。

由于从未将值分配给01属性,因此HasProperty测试给出false,因此If规则将其跳过

答案 2 :(得分:1)

.every()的文档组成:

  

回调仅被调用   用于已分配值的数组索引;它不被调用   用于已删除或从未分配的索引   值。

因此,您正在使用带有array1真实值的.every()调用:

const arr1 = [, , 3, 4]

arr1.every((x, idx) => {
 console.log(`element: ${x}`, `index: ${idx}`);
 return true;
})

答案 3 :(得分:1)

当HasProperty为false时,内置的迭代函数(将由其他人描述并在规范中定义)将跳过值。

您可以为all创建自己的垫片,该垫片将检查每个值。这将是原型的扩展。另外,如果将此代码用于更广泛的范围,则将其转换为函数会是更好的设计,并且需要稍有不同的调用。

const arr1 = [, , 3, 4];
const arr2 = [1, 2, 3, 4];

Array.prototype.all = function(callback){
 for(let i = 0; i < this.length; i++){
     if(callback(this[i],i,this)) return false;
 }
 return true;
};

const result2 = arr1.all((item, index) => item === arr2[index]);
console.log(result2); // false