稀疏数组并减少 JavaScript
Sparse arrays and reduce in JavaScript
人们会认为在 JavaScript 中:
var array = [1,2,undefined,4];
等同于:
var array = [1,2];
array.length = 3;
array.push(4);
但事实并非如此。此代码显示它:
var array1 = [1,2];
array1.length = 3;
array1.push(4);
var array2 = [1,2,undefined,4];
traverseArray(array1);
traverseArray(array2);
function traverseArray(array) {
console.log("trying: " + array);
console.log("reduce:");
array.reduce(function(prev, current, index, array) {
if(current === undefined) {
console.log("Found undefined");
}
console.log(index+": " +current);
}, undefined);
console.log("for loop:")
for(var i=0;i < array.length;i++) {
var current = array[i];
console.log(i+": " +current);
}
console.log();
}
输出:
trying: 1,2,,4
reduce:
0: 1
1: 2
3: 4
for loop:
0: 1
1: 2
2: undefined
3: 4
trying: 1,2,,4
reduce:
0: 1
1: 2
Found undefined
2: undefined
3: 4
for loop:
0: 1
1: 2
2: undefined
3: 4
为什么 array1 中的 undefined 与 array2 中的 undefined 不同,为什么 for 循环的行为相同但 reduce 不同?
apsillers 在评论中指出了这一点。 . .不同之处在于,在 array2
中,您实际上已将 undefined
值分配给数组中的第三个元素(即在索引 2 处),而在 array1
中,您有两个元素最初,改变长度属性,然后在第四个位置添加第三个元素。
以下是来自 MDN 的相关部分,解释了为什么区别很重要:
- 来自
Array.length
上的 page:
When you extend an array by changing its length property, the number of actual elements does not increase; for example, if you set length to 3 when it is currently 2, the array still contains only 2 elements. Thus, the length property says nothing about the number of defined values in the array.
- 来自
Array.push()
上的 page:
The push method relies on a length property to determine where to start inserting the given values.
这里的关键是,length
属性 确实是一个非常简单的 属性,它与数组的内容没有任何内在联系。只是因为Array
的各种方法恰好也维护属性,因为它们"do their work",所以我的行为就好像是
因此,在 array2
中,代码实际上报告了您分配给 array2[2]
的 undefined
值,而在 array1
中,该代码将 array1[2]
处缺少值解释为 undefined
.
array1
具有三个以数字命名的属性:0
、1
和 3
.
array2
有四个以数字命名的属性:0
、1
、2
和 3
。名为 2
的 属性 的值恰好是 undefined
.
当你向一个对象询问它没有的 属性 的值时,结果是 undefined
.
在 for
循环中,您向每个数组询问其名为 0
、1
、2
和 3
的属性的值。对于 array1
,名为 2
的 属性 不存在,因此 属性 访问会产生 undefined
。对于array2
,属性确实存在,但它的值实际上是undefined
,所以你得到同样的结果。
另一方面,reduce
仅对实际存在的属性进行操作。 From the ECMAScript specification,这就是 reduce
循环数组的方式,使用计数器 k
:
- Repeat, while k < len
- Let Pk be ToString(k).
- Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
- If kPresent is true, then... [use the value at index k for the reduce call]
因此,我们可以看到索引仅在通过 [[HasProperty]] 检查时才使用。 array1
没有名为 2
的 属性,因此跳过该索引。
人们会认为在 JavaScript 中:
var array = [1,2,undefined,4];
等同于:
var array = [1,2];
array.length = 3;
array.push(4);
但事实并非如此。此代码显示它:
var array1 = [1,2];
array1.length = 3;
array1.push(4);
var array2 = [1,2,undefined,4];
traverseArray(array1);
traverseArray(array2);
function traverseArray(array) {
console.log("trying: " + array);
console.log("reduce:");
array.reduce(function(prev, current, index, array) {
if(current === undefined) {
console.log("Found undefined");
}
console.log(index+": " +current);
}, undefined);
console.log("for loop:")
for(var i=0;i < array.length;i++) {
var current = array[i];
console.log(i+": " +current);
}
console.log();
}
输出:
trying: 1,2,,4
reduce:
0: 1
1: 2
3: 4
for loop:
0: 1
1: 2
2: undefined
3: 4
trying: 1,2,,4
reduce:
0: 1
1: 2
Found undefined
2: undefined
3: 4
for loop:
0: 1
1: 2
2: undefined
3: 4
为什么 array1 中的 undefined 与 array2 中的 undefined 不同,为什么 for 循环的行为相同但 reduce 不同?
apsillers 在评论中指出了这一点。 . .不同之处在于,在 array2
中,您实际上已将 undefined
值分配给数组中的第三个元素(即在索引 2 处),而在 array1
中,您有两个元素最初,改变长度属性,然后在第四个位置添加第三个元素。
以下是来自 MDN 的相关部分,解释了为什么区别很重要:
- 来自
Array.length
上的 page:
When you extend an array by changing its length property, the number of actual elements does not increase; for example, if you set length to 3 when it is currently 2, the array still contains only 2 elements. Thus, the length property says nothing about the number of defined values in the array.
- 来自
Array.push()
上的 page:
The push method relies on a length property to determine where to start inserting the given values.
这里的关键是,length
属性 确实是一个非常简单的 属性,它与数组的内容没有任何内在联系。只是因为Array
的各种方法恰好也维护属性,因为它们"do their work",所以我的行为就好像是
因此,在 array2
中,代码实际上报告了您分配给 array2[2]
的 undefined
值,而在 array1
中,该代码将 array1[2]
处缺少值解释为 undefined
.
array1
具有三个以数字命名的属性:0
、1
和 3
.
array2
有四个以数字命名的属性:0
、1
、2
和 3
。名为 2
的 属性 的值恰好是 undefined
.
当你向一个对象询问它没有的 属性 的值时,结果是 undefined
.
在 for
循环中,您向每个数组询问其名为 0
、1
、2
和 3
的属性的值。对于 array1
,名为 2
的 属性 不存在,因此 属性 访问会产生 undefined
。对于array2
,属性确实存在,但它的值实际上是undefined
,所以你得到同样的结果。
另一方面,reduce
仅对实际存在的属性进行操作。 From the ECMAScript specification,这就是 reduce
循环数组的方式,使用计数器 k
:
- Repeat, while k < len
- Let Pk be ToString(k).
- Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
- If kPresent is true, then... [use the value at index k for the reduce call]
因此,我们可以看到索引仅在通过 [[HasProperty]] 检查时才使用。 array1
没有名为 2
的 属性,因此跳过该索引。