68

Having googled for it I found two solutions:

    var data = [...Array(10).keys()];
console.log(data);
    var data1 = Array(8).fill().map((_, i) => i);
console.log(data1);

data1 displays [0, 1, ..., 7] however data just displays [[object Array Iterator]] how do I actually see the numbers.

I need it for some iterations over numbers (part of Euler project).

Previously I did a lot of Euler challenges in Python. Now I decided I'll revisit it and do as much as I can in JS (as much ES6 syntax as possible) to help me develop my js skills.

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Wasteland
  • 4,889
  • 14
  • 45
  • 91
  • 3
    If I run `var data = [...Array(10).keys()];` in my browser (latest stable Chrome) I see the numbers listed out. I see `ArrayIterator` if I only do `Array(10).keys()`. – Mike Cluck Oct 07 '16 at 19:39
  • 1
    Is it something to do with codepen? http://codepen.io/wasteland/pen/QKQGNo/?editors=1111 – Wasteland Oct 07 '16 at 19:43
  • 2
    @Wasteland It has to do with Babel, which is being used at that specific code pen – Madara's Ghost Oct 07 '16 at 19:45
  • 2
    It has to do with CodePen's use of Babel. I'm not sure what version they're running but if you disable the Babel preprocessor, everything will be correct. You can run this code [on the Babel website](https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=true&presets=es2015&experimental=true&loose=false&spec=false&code=var%20data%20%3D%20%5B...Array(10).keys()%5D%3B%0Aconsole.log(data)%3B) and you'll still see the result you expect. – Mike Cluck Oct 07 '16 at 19:46
  • Thanks. Isn't babel required for ES6 features? – Wasteland Oct 07 '16 at 20:14

6 Answers6

139

Here is a simple solution that works in codepen:

Array.from(Array(10).keys())

To be clear, Array.from() and Array.keys() require an ES6 polyfill in order to work in all browsers.

Mouad Debbar
  • 3,126
  • 2
  • 20
  • 20
74

A tour of Array.from thru practical examples

Array.from also accepts a second argument which is used as a mapping function

let out = Array.from(Array(10), (_,x) => x);
console.log(out);
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

This is nice to know because you might want to generate arrays that are sometimes more complex than just 0 thru N.

const sq = x => x * x;
let out = Array.from(Array(10), (_,x) => sq(x));
console.log(out);
// [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Or you can make arrays out of generators, too

function* range(start, end, step) {
  while (start < end) {
    yield start;
    start += step;
  }
}

let out = Array.from(range(10,20,2));

console.log(out); // [10, 12, 14, 16, 18]

Array.from is just massively powerful. People don't even realize its full potential yet.

const ord = x => x.charCodeAt(0);
const dec2hex = x => `0${x.toString(16)}`.substr(-2);

// common noob code
{
  let input = "hello world";
  let output = input.split('').map(x => dec2hex(ord(x)));
  
  console.log(output);
  // ["68", "65", "6c", "6c", "6f", "20", "77", "6f", "72", "6c", "64"]
}

// Array.from
{
  let input = "hello world";
  let output = Array.from(input, x => dec2hex(ord(x)));
  
  console.log(output);
  // ["68", "65", "6c", "6c", "6f", "20", "77", "6f", "72", "6c", "64"]
}
Mulan
  • 129,518
  • 31
  • 228
  • 259
35

It seems the problem is that codepen precompiles your code using babel es2015-loose.

In that mode, your

[...Array(10).keys()];

becomes

[].concat(Array(10).keys());

And that's why you see an array containing an iterator.

With es2015 mode you would get

function _toConsumableArray(arr) {
  if (Array.isArray(arr)) {
    for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
      arr2[i] = arr[i];
    }
    return arr2;
  } else {
    return Array.from(arr);
  }
}
[].concat(_toConsumableArray(Array(10).keys()));

which would behave as desired.

See ②ality - Babel 6: loose mode for more information about the modes.

Oriol
  • 274,082
  • 63
  • 437
  • 513
35

All of the other answers here create a temporary intermediate array, which isn't necessary.

Array.from({ length: 10 }, (_, i) => i)

This is essentially a map function where you map from array index to whatever you'd like, for any number of elements.

murrayju
  • 1,752
  • 17
  • 21
  • 2
    This is by far the most elegant method and likely most performant as well using an object with a length property to pose as an iterable and the map fn integrated in the same "loop" – Jax Cavalera Sep 23 '20 at 21:58
20

Further refinement, produces an array with value starting from 1:

Array.from(Array(10).keys(), n => n + 1)
Dwight Rodriques
  • 1,382
  • 1
  • 12
  • 11
10

Here is a range function which takes start, end, and a step parameter. It returns an array starting a from start upto (but excluding) the end number with increments of size step.

const range = (start, end, step) => {
  return Array.from(Array.from(Array(Math.ceil((end-start)/step)).keys()), x => start+ x*step);
}

console.log(range(1, 10, 1));
//[1, 2, 3, 4, 5, 6, 7, 8, 9]

console.log(range(0, 9, 3));
//[0, 3, 6]

console.log(range(10, 30, 5));
//[10, 15, 20, 25]

Taking a step further, if you want a range that includes the end as well.

const inclusiveRange = (start, end, step) => {
  return Array.from(Array.from(Array(Math.ceil((end-start+1)/step)).keys()), x => start+ x*step);
}

console.log(inclusiveRange(1, 10, 1));
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

console.log(inclusiveRange(0, 9, 3));
// [0, 3, 6, 9]

console.log(inclusiveRange(10, 30, 5));
//[10, 15, 20, 25, 30]
Pranav Shukla
  • 2,206
  • 2
  • 17
  • 20