Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Array.apply(null, [args]) act inconsistently when dealing with sparse arrays?

I recently discovered the following snippet of code on SO to aid in quickly populating an array with default values:

Array.apply(null, new Array(3)).map(function() {return 0;});

Given the behavior of the Array constructor and the apply method, the above snippet can also be rewritten as such:

Array.apply(null, [undefined, undefined, undefined]).map(function() {return 0;});

This technique is also useful when dealing with sparse arrays that you wish to populate with default values:

var sparseArr = [3,,,4,1,,],
    denseArr = Array.apply(null, sparseArr).map(function(e) {
      return e === undefined ? 0 : e;
    });

// denseArr = [3,0,0,4,1,0]

However it is therein that two oddities arise:

  1. If the final term of of sparseArr is undefined, that term is not mapped in denseArr
  2. If sparseArr contains only a single term (e.g. sparseArr = [1]) or a single term followed by a single trailing undefined term (e.g. sparseArr = [1,]), the resulting denseArr equals [undefined x 1]

Can anyone explain this behavior?

like image 701
wvandaal Avatar asked Apr 08 '14 23:04

wvandaal


2 Answers

new Array(3) […] can also be rewritten as [undefined, undefined, undefined]

No - as you just have seen, the array constructor creates sparse arrays so it should be rewritten as [,,,].

If the final term of of sparseArr is undefined

Nope. You're forgetting about trailing commata, which are optional since EcmaScript 5. Actually [1] is just equivalent to [1,] (both have a length of 1).

To get sparse "slots", you will have to add additional commata:

[] // empty array
[,] // empty array
[,,] // [undefined x 1]
[,,,] // [undefined x 2]

If sparseArr contains only a single term, the resulting denseArr equals [undefined x N]

Consider what it means to call the apply method:

Array.apply(null, [3,,4,1]) ≡ Array(3, undefined, 4, 1)
Array.apply(null, [3,4]) ≡ Array(3, 4)
Array.apply(null, [1]) ≡ Array(1)

And you know what the Array constructor does when being called with a single numeric arguments - it creates a sparse array of that length…

like image 130
Bergi Avatar answered Sep 25 '22 09:09

Bergi


You can have a trailing comma in arrays since ECMA 262. Its presence doesn't modify the content of the array in any way.

If you have two or more consecutive non trailing commas inside an array, their content is set as undefined.

Note: since undefined in arrays has nonstandard behaviour in IE<9 I would avoid using it there. Use null instead.

The fact that you have surprising results when sparseArr contains one item is because Array has two different constructors: if you pass it multiple arguments it creates an array with that sequence, if you pass it a single number it creates an array of length "number" filled with undefined.

new Array(1, 2, 3)
=> [1, 2, 3]

new Array(2)
=> [undefined, undefined]
like image 43
Riccardo Galli Avatar answered Sep 22 '22 09:09

Riccardo Galli