Reputation: 35
One would think that in JavaScript:
var array = [1,2,undefined,4];
is the same as:
var array = [1,2];
array.length = 3;
array.push(4);
but it's not. This code shows it:
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();
}
Output:
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
Why is undefined in array1 not the same as undefined in array2 and why does the for loop act the same but reduce does not?
Upvotes: 2
Views: 547
Reputation: 7950
apsillers nailed it in the comments . . . the difference is that in array2
you have actually assigned an undefined
value to the 3rd element in the array (i.e., at index 2), where as, in array1
, you have two elements initially, change the length property, and then add a third element in the forth position.
Here are the relevent sections from MDN that explains why the distinction is important:
Array.length
: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()
:The push method relies on a length property to determine where to start inserting the given values.
The key here, is really that the length
property is really, simple a property that is in no way inherantly tied to the contents of the array. It is simply because the various methods of Array
also happen to maintain that property, as they "do their work", that I behaves as if it is.
So, as a result, in array2
, the code is actually reporting back the undefined
value that you assigned to array2[2]
, whereas, with array1
, the code is interpreting the absence of a value at array1[2]
as undefined
.
Upvotes: 3
Reputation: 115940
array1
has three numerically-named properties: 0
, 1
, and 3
.
array2
has four numerically-named properties: 0
, 1
, 2
, and 3
. The value of the property named 2
happens to be undefined
.
When you ask an object for the value of a property it doesn't have, the result is undefined
.
In the for
loop, you ask each array for the values of its properties named 0
, 1
, 2
, and 3
. For array1
, the property named 2
does not exist, so the property access produces undefined
. For array2
, the property does exist, but its value actually is undefined
, so you get the same result.
On the other hand, reduce
only operates on properties that actually exist. From the ECMAScript specification, this is how reduce
loops over arrays, using a counter 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]
So, we can see that an index is only used if passes a [[HasProperty]] check. array1
does not have a property named 2
, so that index is skipped.
Upvotes: 4