5

I'm trying to understand the difference between an 'empty' sparse array (e.g. new Array(3)) and an equivalent 'empty' dense array (array with 3 undefined entries).

I can create an array with 3 undefined values these two ways:

var sparse = new Array(3);
// or
var sparse = [,,,];

var dense = Array.apply(null, Array(3)); // See dense array link below

Dense Arrays

If I do console.log for either of these the result is:

[undefined, undefined, undefined]

If I loop over each array to compare it against the other one they will strictly match:

console.log(sparse.length === dense.length);

// true

for (var i = 0; i < dense.length; i++) {
  console.log(i +':'+ (dense[i] === sparse[i]));
}

// '0:true'
// '1:true'
// '2:true'

However, if I use .forEach (or map, reduce, etc) then the callback will never be called on the sparse array but will be called three times on the dense one:

sparse.forEach(function(val,i){
   console.log(i +':'+ val);
});

// Nothing. No-op.

dense.forEach(function(val,i){
   console.log(i +':'+ val);
});

// '0:undefined'
// '1:undefined'
// '2:undefined'

So my questions are:

  1. If they both have the same length, indexes, and values how is one iterable but the other isn't?
  2. What is the reason for the difference?
  3. What is the best way to determine if an array is sparse or dense?
9
  • This is covered in the EMCAScript specification under .. forEach. Basically it only "runs" for elements that have the property (denoted by the index) assigned any value (including undefined). Just because accessing an unassigned index returns undefined does not mean that it is assigned undefined. (There are also duplicate questions.) Commented Mar 10, 2015 at 21:06
  • 1
    Related: stackoverflow.com/questions/11808946/… , stackoverflow.com/a/9329476/2864740 Commented Mar 10, 2015 at 21:08
  • I saw both of those related questions but I don't feel like they are really asking all of the same questions. For instance what is the rationale for why [,,,] and new Array(2) are equivalent but [undefined,undefined] while looking very similar is actually very different. It is like saying a variable doesn't exist until it explicitly has a value set. Commented Mar 10, 2015 at 21:31
  • I'm more interested in the why than the what. Like why 0.1 + 0.2 !== 0.3. The why is far more interesting. Commented Mar 10, 2015 at 21:37
  • But the why .. is already covered. And if meaning "why was it done like that?" then 9/10 times it's a question without a good objective (and real why) answer but rather one that begs specuation .. Commented Mar 10, 2015 at 22:14

1 Answer 1

4
  1. If they both have the same length, indexes, and values how is one iterable but the other isn't?

These functions are explicitly documented to perform this way. Both arrays are iteratable, but forEach/map/etc explicitly skips indices which are not in the array:

var sparse = new Array(3);
var dense = Array.apply(null, Array(3)); // See dense array link belo

1 in sparse; // false
1 in dense; // true

// Sparse can still be iterated over
sparse[100] = 'a'
sparse.forEach(function (n, i) { console.log(n, i) }); // a 100
  1. What is the reason for the difference?

Presumably an explicit decision was made to omit indices which don't exist

  1. What is the best way to determine if an array is sparse or dense?

You can use the following:

function isSparse(array) {
  for (var i = 0; i < array.length; ++i) {
    if (!i in array)
      return true;
  return false;
}

RE: Your comment

There has got be a reason for why [,,,] doesn't have indexes but [undefined, undefined, undefined] does.

There doesn't have to be a reason, that's just the way they're built. One has keys, the other doesn't.

Look:

Object.keys(Array(3)) // => []
Object.keys(['a','b']) // => ["0", "1"]
Sign up to request clarification or add additional context in comments.

9 Comments

There has got be a reason for why [,,,] doesn't have indexes but [undefined, undefined, undefined] does.
There might not be a reason but typically there is, even for the most idiosyncratic stuff. But [,,,] being meaningfully different than [undefined,undefined,undefined] is like var a; being meaningfully different from var a = undefined; which would be really odd.
@pseudosavant No, it's like alert(a) being meaningfully different than var a; alert(a), which they are. The first one raises an error because a is not defined, the second one alerts undefined. This whole conversation surrounds the difference between sparse and dense arrays, so you already admit that they are different things, so why are you surprised that they have different behaviors?
I don't want to be argumentative. I just want to dig deeper on this. This is the only place in JS that I can think of where whether you assign an undefined value or just don't assign a value at all where you end up with a meaningfully different result. Calling function fn(v) {} like this fn() or this fn(undefined) is exactly the same. var a; is exactly the same as var a = undefined;. On the other hand you can't define an object with properties that don't actually exist (e.g. {,,,,}) like you can with an array (e.g. [,,,,]).
@pseudosavant That still isn't equivalent. It doesn't matter how you call fn(v), inside that function, v is still declared, and it doesn't matter whether you use var a or var a = undefined, because a is still declared. These are not the same thing as attempting to enumerate properties on an object which do not exist.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.