901

Most of the tutorials that I've read on arrays in JavaScript (including w3schools and devguru) suggest that you can initialize an array with a certain length by passing an integer to the Array constructor using the var test = new Array(4); syntax.

After using this syntax liberally in my js files, I ran one of the files through jsLint, and it freaked out:

Error: Problem at line 1 character 22: Expected ')' and instead saw '4'.
var test = new Array(4);
Problem at line 1 character 23: Expected ';' and instead saw ')'.
var test = new Array(4);
Problem at line 1 character 23: Expected an identifier and instead saw ')'.

After reading through jsLint's explanation of its behavior, it looks like jsLint doesn't really like the new Array() syntax, and instead prefers [] when declaring arrays.

So I have a couple questions:

First, why? Am I running any risk by using the new Array() syntax instead? Are there browser incompatibilities that I should be aware of?

And second, if I switch to the square bracket syntax, is there any way to declare an array and set its length all on one line, or do I have to do something like this:

var test = [];
test.length = 4;
simhumileco
  • 31,877
  • 16
  • 137
  • 115
Michael Martin-Smucker
  • 11,927
  • 7
  • 31
  • 36
  • 1
    [**standard js** also advise](http://eslint.org/docs/rules/no-array-constructor) **against** using `new Array()` in general, but it's okay with specifying size. I think it all comes down to code consistency through the whole context. – cregox Apr 01 '17 at 14:02
  • 1
    For those looking to preallocate more rigid array structures, there are [Typed Arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays). Note that [performance benefits may vary](https://stackoverflow.com/a/24855023/10924868) – rovyko Feb 27 '19 at 23:51
  • Please take a look at the following benchmark which provides different solutions: https://www.measurethat.net/Benchmarks/Show/9721/0/initializing-array-with-n-undefined-items – AmazingTurtle Sep 23 '20 at 12:53

20 Answers20

1099
  • Array(5) gives you an array with length 5 but no values, hence you can't iterate over it.

  • Array.apply(null, Array(5)).map(function () {}) gives you an array with length 5 and undefined as values, now it can be iterated over.

  • Array.apply(null, Array(5)).map(function (x, i) { return i; }) gives you an array with length 5 and values 0,1,2,3,4.

  • Array(5).forEach(alert) does nothing, Array.apply(null, Array(5)).forEach(alert) gives you 5 alerts

  • ES6 gives us Array.from so now you can also use Array.from(Array(5)).forEach(alert)

  • If you want to initialize with a certain value, these are good to knows...
    Array.from('abcde'), Array.from('x'.repeat(5))
    or Array.from({length: 5}, (v, i) => i) // gives [0, 1, 2, 3, 4]

Qwerty
  • 29,062
  • 22
  • 108
  • 136
Ruben Stolk
  • 12,386
  • 2
  • 18
  • 12
  • 26
    This is what I was looking for. I wanted to apply a map over a logical sequence; this should do it. Thank you! –  May 20 '15 at 18:55
  • 3
    why Array.apply() gives it undefined as value? – wdanxna Jun 01 '15 at 08:21
  • 5
    @wdanxna when `Array` is given multiple arguments, it iterates over the `arguments` object and explicitly applies each value to the new array. When you call `Array.apply` with an array or an object with a length property `Array` is going to use the length to explicitly set each value of the new array. This is why `Array(5)` gives an array of 5 elisions, while `Array.apply(null, Array(5))` gives an array of 5 undefined's. For more information, see [this](http://stackoverflow.com/a/20066663/983194) answer. – KylePlusPlus Jul 10 '15 at 04:40
  • 2
    is there difference between Array(5) and new Array(5)? – Petr Hurtak Nov 14 '15 at 15:45
  • The last example can be simplified. To have 5 alerts you can do `Array.apply(null, Array(5))..forEach(alert)`. The map function is useless. – Loic Dec 14 '15 at 22:36
  • 6
    The `Array.apply(null, Array(5))` can also be written as `Array.apply(null, {length: 5})`. There really is not much difference, but the latter is unambiguously clear that the intent is to create an array of `length 5`, and not an array containing `5` – AlexMorley-Finch Aug 10 '16 at 09:23
  • If you need create array with empty string inside you can also do like this `Array.apply(null, Array(49)).map(function () { return ""; })` – Vasilij Altunin Mar 02 '17 at 23:29
  • Creating initialized 2d array `Array.from(Array(5)).map(() => Array.from(Array(5)).fill(0))` – Vyacheslav A. Nov 04 '17 at 17:59
  • 1
    The trick with `{length:5}` can also be used with the new `.from` method like this `Array.from({length: 5}, (v, i) => i)` – Qwerty Mar 11 '18 at 13:58
  • I believe that ES7 this is a "prettier" way to do the things – William Prigol Lopes Mar 26 '20 at 11:11
  • let arr = [...Array(10)].fill(0); – Sandeep Sep 12 '22 at 10:34
  • Use `map` instead of `forEach` to create the array instead of just doing something _n_ times. – tim-phillips Apr 19 '23 at 19:04
538

With ES2015 .fill() you can now simply do:

// `n` is the size you want to initialize your array
// `0` is what the array will be filled with (can be any other value)
Array(n).fill(0)

Which is a lot more concise than Array.apply(0, new Array(n)).map(i => value)

It is possible to drop the 0 in .fill() and run without arguments, which will fill the array with undefined. (However, this will fail in Typescript)

AP.
  • 8,082
  • 2
  • 24
  • 33
  • Unfortunately fill is not yet supported in ie: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill?v=control – dkniffin May 17 '17 at 14:46
  • 1
    @AralRoca You could always use the [Polyfill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill?v=control#Polyfill) provided on the MDN page, or consider using [Modernizr](https://modernizr.com/download?es6array-setclasses). – AP. Jul 13 '17 at 14:45
  • 5
    Yes, please try it before you comment – AP. Nov 24 '17 at 15:53
  • Can someone tell me where `Array(n)` is documented? – Garret Wilson Jan 23 '18 at 15:53
  • 2
    @GarretWilson and @Christian It's [__in the spec__](https://www.ecma-international.org/ecma-262/6.0/#sec-array-objects). _`When Array is called as a function rather than as a constructor, it also creates and initializes a new Array object. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments`_ – AP. Jan 23 '18 at 17:45
  • 1
    @AP., The zero is redundant. Do `Array(n).fill()` – Pacerier May 19 '18 at 17:15
  • 10
    @Pacerier I don't think the 0 was redundant. According to es6 type definition, this is the function signature: fill(value: T, start?: number, end?: number): this; Hence the fill value does not seem optional. Typescript compilation will fail as the function call is written above. – Micha Schwab Jun 14 '18 at 16:27
  • very clear, easy-to-understand way to initialize an array and fill it with a value (like all 0, for instance) – rpivovar Nov 02 '19 at 22:43
  • 1
    fill only works when initializing the array with the same value. Array(10).fill(math.random()) will not produce 10 random values, but only one. – Rodrigo Amaral Nov 02 '20 at 02:12
  • Yes, so if you needed to do that you'd simply do `Array(10).fill().map(_ => math.random())` Since your array was created correctly and can be mapped (vectorized) – AP. Nov 02 '20 at 05:59
498
  1. Why do you want to initialize the length? Theoretically there is no need for this. It can even result in confusing behavior, because all tests that use the length to find out whether an array is empty or not will report that the array is not empty.
    Some tests show that setting the initial length of large arrays can be more efficient if the array is filled afterwards, but the performance gain (if any) seem to differ from browser to browser.

  2. jsLint does not like new Array() because the constructer is ambiguous.

    new Array(4);
    

    creates an empty array of length 4. But

    new Array('4');
    

    creates an array containing the value '4'.

Regarding your comment: In JS you don't need to initialize the length of the array. It grows dynamically. You can just store the length in some variable, e.g.

var data = [];
var length = 5; // user defined length

for(var i = 0; i < length; i++) {
    data.push(createSomeObject());
}
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 22
    The number of objects in the array is user-defined, so I was letting the user pick a number, then initializing the array with that many slots. Then I run a `for` loop that iterates over the length of the array and fills it. I guess there would be other ways to do this in JavaScript, so the real answer to "Why do I want to do this?" is "Because of old habits that formed while programming in other languages." :) – Michael Martin-Smucker Jan 31 '11 at 14:39
  • 4
    @mlms Just let the for loop iterate over the user-defined number instead of having to set the array length and then iterate over it. Doesn't that make more sense to you? – Šime Vidas Jan 31 '11 at 14:43
  • @Šime, yeah, that's what I was realizing when I was typing my comment. It makes perfect sense, but it's the kind of thing I wouldn't do in C#, which I learned before (and used more) than JavaScript. – Michael Martin-Smucker Jan 31 '11 at 14:46
  • 207
    Why do you want to initialize the length? Theoretically there is no need for this. And all tests that use the length to find out whether an array is empty or not will fail. Um, *performance* perhaps? It's faster to set a pre-existing element of an array than it is to add it on the fly. – codehead Mar 22 '11 at 01:03
  • 15
    @codehead: in response to this quote: "It's faster to set a pre-existing element of an array than it is to add it on the fly.": note that `new Array(10)` does not create an array with 10 undefined elements. It simply creates an empty array with a length of 10. See this answer for the nasty truth: http://stackoverflow.com/questions/18947892/creating-range-in-javascript-strange-syntax – Milimetric Apr 24 '15 at 22:12
  • 2
    Re: *Why do you want to initialize the length? Theoretically there is no need for this.* -- fwiw, there's [this](http://stackoverflow.com/a/1877479/1028230): `Array(11).join("a")` Seem hard to make JSLint happy there. Though, as Milimetric suggests, [it looks like you just have to set the array's length to `n` to dupe the constructor](http://stackoverflow.com/a/18949651/1028230) -- `arr=[];arr.length=n+1;str=arr.join(repeatMe);`. Argh. Code smell. – ruffin May 11 '15 at 18:32
  • @Kristijan: `length` is a scalar. I'm not accessing the length of an array here. There is no advantage using `while`. – Felix Kling Jul 07 '15 at 15:22
  • @FelixKling sorry, commented it weird probably, I see an advantage in shorter code as there is no importance of having 'i' to be the correct order in this case, so a while(i--) is shorter to write. – Kristijan Jul 07 '15 at 15:36
  • NEVER user new Array(INT) ! https://coderwall.com/p/h4xm0w/why-never-use-new-array-in-javascript – Karl Adler May 22 '17 at 12:26
  • @abimelex i was going to respond with how you shouldn't not use a feature because the language has a few getchas(which all languages have unless they don't care about backward compatibility, very recent, and only available to people who you studied to know what they consider a getcha in the current year); but after a few benchmarks, I found that `var a = new Array(400000)` often slower than a `var a = []; for (var i = 0; i < 400000; ++i) { a[i] = 0; }` Both taking 1 or 2 milliseconds. Very strange considering new constructors tend to be one of the fastest things in JavaScript. – Dmytro Nov 25 '17 at 15:39
  • 62
    "Why do you want to ..." gets asked so many times on SO. FWIW I think when someone posts a question it is reasonable to assume that they have a legitimate use case in mind and start from there. – Michael Jun 14 '19 at 16:28
  • 4
    @Michael: Knowing the actual use case enables us to potentially provide better solutions. This is known as [the XY problem](https://en.wikipedia.org/wiki/XY_problem). – Felix Kling Jun 14 '19 at 17:19
  • 2
    What if I want to fill the array non-sequentially... or have double-arrays (or other items that require acting on an existing object)? – lowcrawler Oct 16 '19 at 23:14
  • 9
    This another "answer" that is just arguing against the poster, and never actually answers the question. If you don't want to initialize the length of an array, then don't do so in your code. Otherwise, don't tell someone else what they can and can't do in theirs. If you can't answer the question, then just don't. – Mike Apr 22 '20 at 20:14
  • 4
    @FelixKling a "why" should never be part of the answer, but can be a comment. A good reason to initialize an array is that you want to map over it to populate it, to avoid imperative code. – user239558 Sep 30 '20 at 13:45
  • This is also just a faster way of writing a large array of values. For example rather than hardcoding [0,1,2,3,4,5,6 .... 100] you can write new Array(100).map((x,i) => i); – Harrison Cramer Jan 24 '21 at 17:00
  • 1
    This answer is exactly the reason why js devs have a reputation for knowing little about computer science. The answer to the rhetorical question, "why would you want to initialize length?", should be trivially obvious to any who knows the basics about data structures. At the lower levels, to which js compiles, there is no such thing as a dynamic array, meaning that all arrays have set lengths. There are ways to make arrays behave dynamically, but they are not computationally free. Therefore, by statically setting the length of an array, you bypass that overhead. There's your answer. – John Miller Jun 06 '21 at 15:59
  • @JohnMiller: You are right but you are also making assumptions that the length provided trickles down to the "lower levels". But does it? Have you looked at how engines implement JavaScript arrays? JS arrays cannot directly be mapped to lower level array data structure, given their heterogeneous nature. I'm sure engines do optimize them if possible, but from a JS perspective, arrays are just objects, and the length is just a (special) property. So in reality the issue is much more nuanced... – Felix Kling Jun 07 '21 at 09:00
  • "Why do you want to initialize the length?" That's none of your business. Answer the question. Otherwise, it belongs in a comment. – Joel Day Sep 06 '21 at 02:10
  • @JoelDay: I agree and disagree. Knowing what the intentions behind the questions is, what the actual problem is that they are trying to solve is important and will change the answer. That's what the whole [X Y problem](https://xyproblem.info/) is about. But yes, that clarification question should have been a comment and the OP should have edited their question accordingly. – Felix Kling Sep 06 '21 at 07:41
  • be aware that array length has a setter too. – eomeroff Nov 12 '21 at 15:19
  • @FelixKling, agreed about the XY Problem. I wonder if there's a way SO could accommodate it specifically since it is an almost universal question that comes up. – Joel Day Mar 16 '22 at 18:45
370
[...Array(6)].map(x => 0);
// [0, 0, 0, 0, 0, 0]

OR

Array(6).fill(0);
// [0, 0, 0, 0, 0, 0]

Note: you can't loop empty slots i.e. Array(4).forEach(() => …)


OR

( typescript safe )

Array(6).fill(null).map((_, i) => i);
// [0, 1, 2, 3, 4, 5]

OR

Classic method using a function ( works in any browser )

function NewArray(size) {
    var x = [];
    for (var i = 0; i < size; ++i) {
        x[i] = i;
    }
    return x;
}

var a = NewArray(10);
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Creating nested arrays

When creating a 2D array with the fill intuitively should create new instances. But what actually going to happen is the same array will be stored as a reference.

var a = Array(3).fill([6]);
// [  [6], [6], [6]  ]

a[0].push(9);
// [  [6, 9], [6, 9], [6, 9]  ]

Solution

var a = [...Array(3)].map(x => []);

a[0].push(4, 2);
// [  [4, 2], [], []  ]

So a 3x2 Array will look something like this:

[...Array(3)].map(x => Array(2).fill(0));
// [  [0, 0], [0, 0], [0, 0]  ]

N-dimensional array

function NArray(...dimensions) {
    var index = 0;
    function NArrayRec(dims) {
        var first = dims[0], next = dims.slice().splice(1); 
        if(dims.length > 1) 
            return Array(dims[0]).fill(null).map((x, i) => NArrayRec(next ));
        return Array(dims[0]).fill(null).map((x, i) => (index++));
    }
    return NArrayRec(dimensions);
}

var arr = NArray(3, 2, 4);
// [   [  [ 0,  1,  2,  3 ] , [  4,  5,  6,  7]  ],
//     [  [ 8,  9,  10, 11] , [ 12, 13, 14, 15]  ],
//     [  [ 16, 17, 18, 19] , [ 20, 21, 22, 23]  ]   ]

Initialize a chessboard

var Chessboard = [...Array(8)].map((x, j) => {
    return Array(8).fill(null).map((y, i) => {
        return `${String.fromCharCode(65 + i)}${8 - j}`;
    });
});

// [ [A8, B8, C8, D8, E8, F8, G8, H8],
//   [A7, B7, C7, D7, E7, F7, G7, H7],
//   [A6, B6, C6, D6, E6, F6, G6, H6],
//   [A5, B5, C5, D5, E5, F5, G5, H5],
//   [A4, B4, C4, D4, E4, F4, G4, H4],
//   [A3, B3, C3, D3, E3, F3, G3, H3],
//   [A2, B2, C2, D2, E2, F2, G2, H2],
//   [A1, B1, C1, D1, E1, F1, G1, H1] ]

Math filled values

handy little method overload when working with math


function NewArray( size , method, linear )
{
    method = method || ( i => i ); 
    linear = linear || false;
    var x = [];
    for( var i = 0; i < size; ++i )
        x[ i ] = method( linear ? i / (size-1) : i );
    return x;
}

NewArray( 4 ); 
// [ 0, 1, 2, 3 ]

NewArray( 4, Math.sin ); 
// [ 0, 0.841, 0.909, 0.141 ]

NewArray( 4, Math.sin, true );
// [ 0, 0.327, 0.618, 0.841 ]

var pow2 = ( x ) => x * x;

NewArray( 4, pow2 ); 
// [ 0, 1, 4, 9 ]

NewArray( 4, pow2, true ); 
// [ 0, 0.111, 0.444, 1 ]
Vlad
  • 3,936
  • 1
  • 13
  • 15
  • 2
    `a[0].push(9);` `// [ [6, 9], [6], [6] ]` should be `a[0].push(9);` `// [ [6, 9], [6, 9], [6, 9] ]` because each nested array is stored as a reference, so mutating one array affects the rest. You may have just mistyped it though I think :) – Yao May 10 '20 at 08:07
  • 1
    `[...Array(6)].map(x => 0);` is an excellent solution and was very helpful for me! With a slight modification it can be used to create an array that counts integers (just like your typescript safe example): `[...Array(6)].map((x, i) => i);` results in `[0, 1, 2, 3, 4, 5]` – Joshua Evans Oct 23 '20 at 20:56
  • 1
    Sometimes I don't use the "element/item/first parameter" in the map function because I need only index and I was looking for a best practice to name that parameter. I didn't wanna name it like "x" or "unused" etc. So, using underscore is actually awesome idea! Thanks! `map((_, i) => i)` – cyonder Jul 14 '21 at 19:58
  • I understand you wanted to improve your answer but try not to copy other people's answer just to be upvoted. Thanks. – Michael Mammoliti Oct 24 '21 at 02:39
  • 1
    just noticed u r the one with the shortest answer , very nice – Vlad Oct 25 '21 at 23:57
  • 1
    `Array(Infinity).fill(0)` create your universe! `Array(Infinity).fill(Infinity)` you're God! – ManUtopiK Jan 21 '22 at 21:04
98

The shortest:

let arr = [...Array(10)];
console.log(arr);
Teocci
  • 7,189
  • 1
  • 50
  • 48
Michael Mammoliti
  • 1,517
  • 13
  • 11
  • 15
    Upvoted, but one caveat, you absolutely should not start a line in JS with a `[` without using a `;` since it will attempt to dereference the line above. So a safe way to use this line predictably in any part of the code would be: `;[...Array(1000)]//.whateverOpsNeeded()` – AP. May 29 '18 at 21:15
  • not really. try in developer tools. `[...Array(5)].map((item, index) => ({ index }))` try this as well: `[...Array(5)]; console.log('hello');` – Michael Mammoliti May 30 '18 at 10:14
  • 3
    Try using it in a multi-line js file. If your first line is `const a = 'a'` and the next line `[...Array(5)].//irrelevent`. What do you think the first line would resolve to? It would be `const a = 'a'[...Array(5)]` which would result in: `Uncaught SyntaxError: Unexpected token ...` – AP. Jun 01 '18 at 18:27
  • 8
    That's true but in this case I would say that the problem is somewhere else, semicolons and linting are important nowdays. – Michael Mammoliti Jun 01 '18 at 20:14
  • Right, it was just a disclaimer for any user that if you include a `;` right before your line, like, `;[...Array(5)].map()` you can use this anywhere in your code without having to worry about unintended js behavior. As I said, it is a good answer! :) – AP. Jun 01 '18 at 22:10
  • 9
    @AP that example is exactly the reason why many style guides mandate ending every statement with a semicolon. `const a = 'a'` will be a Lint error in that case. Anyway, it really has nothing to do with this answer. – graup Jul 17 '18 at 10:30
  • If you're using Babel, `loose` has to be `false` for this to work. – luwes Mar 16 '20 at 01:09
  • how about let arr = [...Array(10)].fill(0); – Sandeep Sep 12 '22 at 10:33
64

ES6 introduces Array.from which lets you create an Array from any "array-like" or iterables objects:

Array.from({length: 10}, (x, i) => i);
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In this case {length: 10} represents the minimal definition of an "array-like" object: an empty object with just a length property defined.

Array.from allows for a second argument to map over the resulting array.

AaronDancer
  • 649
  • 1
  • 7
  • 22
Alexander Shutau
  • 2,660
  • 22
  • 32
57

Sparse arrays are here! [2021]

In modern JS engines, sparse arrays are fully supported. You can use [] or new Array(len) in any way you like, even with random access. Dictionary mode seems to be a thing of the past.

In current Chrome (and I guess any V8 environment), Arrays can have a length of up to 2^32-1 and allocation is sparse (meaning empty chunks don't use up any memory):

enter image description here

enter image description here

However, there is a catch

On the one hand, for loops work as intended, however, Array's builtin higher order functions (such as map, filter, find, some etc.) ignore unassigned elements. They require fill (or some other method of population) first:

const a = new Array(10);
const b = new Array(10).fill(0);

a.forEach(x => console.log(x)); // does nothing
b.forEach(x => console.log(x)); // works as intended

Old Version

(I removed most of the old version.) The gist was that creating a large array using new Array(largeNumber) or random accessing an array in places that have not yet been allocated would tumble it into "dictionary mode". Meaning you are using an array with indexes, but under the hood it would use a dictionary to store the values, thus messing with performance, and also with iteration behavior. Luckily that is a thing of the past.

Domi
  • 22,151
  • 15
  • 92
  • 122
  • 2
    6 years later... Anyways, you were probably thinking you were in a different language when you wrote this because you don't actually use int to define an integer in JavaScript (use `let`, `var`, or `const`). I just want to clear things up for the next person who copies StackOverflow code and realizes it doesn't work – sno2 Dec 29 '20 at 02:17
  • 2
    @sno2 There was definitely a typo there. Funnily, a lot of things have changed since then, so I updated the whole thing – Domi Jan 20 '22 at 07:40
  • 3
    you could also just call `.fill` without an argument and then you can iterate over the array: `new Array(10).fill().forEach(i => console.log(i))` – mockingjay Apr 21 '22 at 15:25
30

This will initialize the length property to 4:

var x = [,,,,];
Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • 4
    That's clever. It doesn't have the flexibility of the constructor, because you can't use a variable to set the length, but it does answer my question as I originally phrased it, so +1. – Michael Martin-Smucker Jan 31 '11 at 16:09
  • 14
    Imagine doind that for 300 items when performance would really matter! – Marco Luglio Dec 18 '12 at 22:01
  • @facildelembrar What do you mean? Do *what* for 300 items? – Šime Vidas Dec 18 '12 at 23:53
  • @facildelembrar That would be senseless `:-)` – Šime Vidas Dec 28 '12 at 16:49
  • 10
    There is problably not much performance gain when preallocating an array with such a small size. The performance difference will be better perceived when creating larger arrays. And in those cases, initialize them with commas would be a little bit overwhelming. – Marco Luglio Dec 28 '12 at 16:53
  • @facildelembrar There is no performance gain, AFAIK. In JavaScript, arrays are dynamic hashes, with an ubiquitous `length` property. – Šime Vidas Dec 28 '12 at 16:58
  • 7
    I think that this will yield different results in different browsers because of the final comma, sometimes 4 and sometimes 5, see http://stackoverflow.com/questions/7246618/trailing-commas-in-javascript – jperelli Apr 25 '14 at 23:55
  • 2
    How about `var size = 42; var myArray = eval("["+",".repeat(size)+"]");` ? (Not that serious ;) – xoxox Nov 25 '16 at 18:28
16

The simplest form is to use

Array.from({ length: 3 });

// gives you
[undefined, undefined, undefined]

Unlike Array(3) which will give you an array you can't iterate over. Array.from({ length }) gives you an array you can iterate easily.

Array.from({ length: 3 }).map((e, idx) => `hi ${idx}`);
// ['hi 1', 'hi 2', 'hi 3']
Haseeb Anwar
  • 2,438
  • 19
  • 22
15

I'm surprised there hasn't been a functional solution suggested that allows you to set the length in one line. The following is based on UnderscoreJS:

var test = _.map(_.range(4), function () { return undefined; });
console.log(test.length);

For reasons mentioned above, I'd avoid doing this unless I wanted to initialize the array to a specific value. It's interesting to note there are other libraries that implement range including Lo-dash and Lazy, which may have different performance characteristics.

christang
  • 533
  • 6
  • 15
  • 7
    The underscore black magic really isn't needed here. Dependencies are like sugar, it seems sweet at first, but before you know it you get diabetes. – Romain Vincent Nov 11 '19 at 14:17
11

Here is another solution

var arr = Array.apply( null, { length: 4 } );
arr;  // [undefined, undefined, undefined, undefined] (in Chrome)
arr.length; // 4

The first argument of apply() is a this object binding, which we don't care about here, so we set it to null.

Array.apply(..) is calling the Array(..) function and spreading out the { length: 3 } object value as its arguments.

zangw
  • 43,869
  • 19
  • 177
  • 214
  • 1
    I don't understand why this answer got a downvote. It's actually a nice hack. Meaning you can't use `new Array(n)` for initializing an array like this `new Array(n).map(function(notUsed,index){...})`, but with this approach, as @zangw mentioned, you can do it. +1 from me. – Victor.Palyvoda Sep 18 '16 at 18:58
  • This is awesome and exactly what I've been looking for a whole 5 years after! kudos to you my friend. If you're wondering, I'm using this in react to render a certain number of children based on an int value that's passed in as a prop. ```Array.apply(null, { length: childrenLength }).map((notUsed, i) => (
    )```
    – George Nov 11 '20 at 17:09
9

Please people don't give up your old habits just yet. There is a large difference in speed between allocating memory once then working with the entries in that array (as of old), and allocating it many times as an array grows (which is inevitably what the system does under the hood with other suggested methods).

None of this matters of course, until you want to do something cool with larger arrays. Then it does.

Seeing as there still seems to be no option in JS at the moment to set the initial capacity of an array, I use the following...

var newArrayWithSize = function(size) {
  this.standard = this.standard||[];
  for (var add = size-this.standard.length; add>0; add--) {
   this.standard.push(undefined);// or whatever
  }
  return this.standard.slice(0,size);
}

There are tradeoffs involved:

  • This method takes as long as the others for the first call to the function, but very little time for later calls (unless asking for a bigger array).
  • The standard array does permanently reserve as much space as the largest array you have asked for.

But if it fits with what you're doing there can be a payoff. Informal timing puts

for (var n=10000;n>0;n--) {var b = newArrayWithSize(10000);b[0]=0;}

at pretty speedy (about 50ms for the 10000 given that with n=1000000 it took about 5 seconds), and

for (var n=10000;n>0;n--) {
  var b = [];for (var add=10000;add>0;add--) {
    b.push(undefined);
  }
}

at well over a minute (about 90 sec for the 10000 on the same chrome console, or about 2000 times slower). That won't just be the allocation, but also the 10000 pushes, for loop, etc..

wils
  • 791
  • 7
  • 7
  • if every time you reach to the end of the array you duplicates it, the complexity of inserting n values is still O(n) so there isn't difference in complexity (but it is slower). – Tomer Wolberg Sep 24 '18 at 08:43
  • Well caught @TomerWolberg, I have changed my wording. It's a matter of whether the push method has higher complexity than the initialisation/copy of an individual member by slice. AFAIK that they are both constant time, at the very least they could be so I've used the word 'speed' instead. – wils Oct 26 '18 at 01:13
8

(this was probably better as a comment, but got too long)

So, after reading this I was curious if pre-allocating was actually faster, because in theory it should be. However, this blog gave some tips advising against it http://www.html5rocks.com/en/tutorials/speed/v8/.

So still being unsure, I put it to the test. And as it turns out it seems to in fact be slower.

var time = Date.now();
var temp = [];
for(var i=0;i<100000;i++){
    temp[i]=i;
}
console.log(Date.now()-time);


var time = Date.now();
var temp2 = new Array(100000);
for(var i=0;i<100000;i++){
    temp2[i] = i;
}
console.log(Date.now()-time); 

This code yields the following after a few casual runs:

$ node main.js 
9
16
$ node main.js 
8
14
$ node main.js 
7
20
$ node main.js 
9
14
$ node main.js 
9
19
j03m
  • 5,195
  • 4
  • 46
  • 50
  • 3
    Interesting, that seemed unexpected, so I made [a JSPerf test](http://jsperf.com/allocating-array-size). The Chrome results match your Node tests, but Firefox and IE are slightly faster when you pre-allocate space for the array. – Michael Martin-Smucker Feb 26 '14 at 15:24
  • 1
    @MichaelMartin-Smucker Wait... does this mean V8 isn't actually fully optimized and perfect?!?!? :P – Piper McCorkle Oct 06 '14 at 23:38
  • @mypal125: In fact it's the other way round. V8 is over-optimized so much that the optimized code path is faster than what used to be the faster code path. And the other browser doesn't have optimizations at all so that the previously faster code path remains faster. Note that in the benchmark that even the "slow" V8 result is faster than the fast results of other browsers. – slebetman Feb 19 '15 at 06:00
  • 1
    @MichaelMartin-Smucker - I just ran your jsperf in Chrome Version 42.0.2311.90 (To be specific - Testing in Chrome 42.0.2311.90 32-bit on Windows Server 2008 R2 / 7 64-bit) and dynamically-sized array was 69% slower. – Yellen Apr 30 '15 at 06:45
  • 1
    Ditto. (I wrote the original node test) In chrome 42.0.2311.90 on windows dynamically sized was 81% slower :). But our original tests were over a year ago now. Time keeps on slippin, slippin.... – j03m Apr 30 '15 at 13:44
  • 1
    Fascinating... from the results on jsperf it looks like pre-allocated got a huge boost in Chrome 38. The future! – Michael Martin-Smucker Apr 30 '15 at 15:37
  • Update for anyone reading this now - Chrome 98 on Windows certainly prefers pre-allocated array lengths, as expected, typically resulting in pre-allocated arrays taking half the time than automatically allocated. – SEoF Feb 23 '22 at 09:58
8
var arr=[];
arr[5]=0;
alert("length="+arr.length); // gives 6
user1067305
  • 3,233
  • 7
  • 24
  • 29
  • 2
    Yes, however console.log(arr) gives ```[5: 0]``` this is a sparse array and probably not what is wanted. – dreftymac Nov 19 '14 at 17:07
  • To explain why you may not want a sparsed array as @dreftymac stated: A sparsed array (includes empty cells) can have unexpected behaviors. For example, if I ran the following code: ```js const foo = []; foo[10] = undefined; ``` The value of `foo` is not `[undefined, undefined undefined, ...]` but `[empty * 9, undefined]`. If you tried to run any of the sequencial array methods (`forEach`, `map`, `reduce`), then you would realize that it doesn't actually iterate through the empty items. They are just dead space. – sno2 Dec 29 '20 at 02:22
4

Assuming that Array's length is constant. In Javascript, This is what we do:

const intialArray = new Array(specify the value);

mohan babu
  • 1,388
  • 2
  • 17
  • 35
3

The array constructor has an ambiguous syntax, and JSLint just hurts your feelings after all.

Also, your example code is broken, the second var statement will raise a SyntaxError. You're setting the property length of the array test, so there's no need for another var.

As far as your options go, array.length is the only "clean" one. Question is, why do you need to set the size in the first place? Try to refactor your code to get rid of that dependency.

Domi
  • 22,151
  • 15
  • 92
  • 122
Ivo Wetzel
  • 46,459
  • 16
  • 98
  • 112
  • Woops, good eye on that second `var test`. That was some sloppy copy-and pasting on my part. – Michael Martin-Smucker Jan 31 '11 at 20:03
  • @IvoWetzel, you want to set the size to improve performance. JS arrays are [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array). If you don't set the size (or rather, it's capacity), JS will allocate a an array of default size. If you then add more elements than can fit, it will have to grow the array, which means that it internally will allocate a new array and then copy all elements. – Domi Jan 04 '14 at 12:01
2

In addition to the answers of others, another clever way is to use Float32Array to create an array and iterate on it.

For this purpose, create an instance from Float32Array with your desired length like this:

new Float32Array(5)

This code returns an array-like that you can convert it to an array with Array.from():

Array.from(new Float32Array(5)) // [0, 0, 0, 0, 0]

You can also use fill() to change the value of items:

Array.from(new Float32Array(5).fill(2)) // [2, 2, 2, 2, 2]

And of course you can iterate on it:

Array.from(new Float32Array(5)).map(item => /* ... */ )
Amir
  • 1,328
  • 2
  • 13
  • 27
1

In most answers it is recommended to fill the array because otherwise "you can't iterate over it", but this is not true. You can iterate an empty array, just not with forEach. While loops, for of loops and for i loops work fine.

const count = Array(5);

Does not work.

console.log('---for each loop:---');
count.forEach((empty, index) => {
    console.log(`counting ${index}`);
});

These work:

console.log('---for of loop:---');
for (let [index, empty] of count.entries()) {
  console.log(`counting for of loop ${index}`);
}

console.log('---for i loop:---');
for (let i = 0, il = count.length; i < il; ++i) {
  console.log(`counting for i loop ${i}`);
}

console.log('---while loop:---');
let index = 0;
while (index < count.length) { 
  console.log(`counting while loop ${index}`); 
  index++; 
}

Check this fiddle with the above examples.

Also angulars *ngFor works fine with an empty array:

<li *ngFor="let empty of count; let i = index" [ngClass]="
  <span>Counting with *ngFor {{i}}</span>
</li>
Wilt
  • 41,477
  • 12
  • 152
  • 203
-2

You can set the array length by using array.length = youValue

So it would be

var myArray = [];
myArray.length = yourValue;
ajoposor
  • 17
  • 5
-5

The reason you shouldn't use new Array is demonstrated by this code:

var Array = function () {};

var x = new Array(4);

alert(x.length);  // undefined...

Some other code could mess with the Array variable. I know it's a bit far fetched that anyone would write such code, but still...

Also, as Felix King said, the interface is a little inconsistent, and could lead to some very difficult-to-track-down bugs.

If you wanted an array with length = x, filled with undefined (as new Array(x) would do), you could do this:

var x = 4;
var myArray = [];
myArray[x - 1] = undefined;

alert(myArray.length); // 4
nickf
  • 537,072
  • 198
  • 649
  • 721