読者です 読者をやめる 読者になる 読者になる

JavascriptでRubyのRange#to_aのような配列を返す方法

javascript

20140115 ES6記法を追加(from jserさん)
 


RubyではRangeオブジェクトは便利なのでよく使います。

>> (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Javascriptだと

Javascriptでも同じようなものが無いのか探してみると、いくつかありました。

1. forで回してArray.push

とりあえず普通に書いてみました。

function range(from, to) {
  var ar = [];
  for (var i=from; i <= to; i++) {
    ar.push(i)
  }
  return ar;
}

range(1,10)
=>  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

2. Underscore.js range を使う

もっとsmartな方法はないかと調べたら undersocre で実装されていました。undersocre 便利。

_.range(1, 11);
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

underscore/underscore.js at master · jashkenas/underscore · GitHub
中身を見ると、結局forで回してArrayに突っ込んでます。

  _.range = function(start, stop, step) {
    if (arguments.length <= 1) {
      stop = start || 0;
      start = 0;
    }
    step = step || 1;

    var length = Math.max(Math.ceil((stop - start) / step), 0);
    var range = Array(length);

    for (var idx = 0; idx < length; idx++, start += step) {
      range[idx] = start;
    }

    return range;
  };

3. 黒魔術

速度は遅いようですが、こういうのもあるようです(あくまで参考)。

Does JavaScript have a range() equivalent? - Stack Overflow

Array.apply(null, Array(5)).map(function (_, i) {return i;});
=> [0, 1, 2, 3, 4]

まだこれは理解できます。
 
JavaScriptで0からn-1までを要素にもつArrayを作成する方法 - blog.scheakur.com
こっちがすごいです。

Array.apply(null, {length: 5}).map(Number.call, Number)
=> [0, 1, 2, 3, 4]

最初の{length: 5} っていうのは思い浮かばないですし、mapの中が意味不明です。
(リンク先はすごい丁寧に解説されています。勉強になりました。)
 
apply、callを使いこなすといろいろできそうですね。

4. immutable-js

いまこれをモリモリ使っている人は少ないと思いますが facebookのimmutable.js を使うと取得できます。
React + immutable.js が流行るんでしょうか。

Immutable.Range(1, 11).toArray();
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

immutable-js/IterableImpl.js at master · facebook/immutable-js · GitHub

  toArray() {
    assertNotInfinite(this.size);
    var array = new Array(this.size || 0);
    this.valueSeq().__iterate((v, i) => { array[i] = v; });
    return array;
  },

5. ES6

id:jser さんに教えていただいたES6記法です。

[...Array(3).keys()]
=> Array [ 0, 1, 2 ]

iterableなobjectはドット3つで展開できるようです。実装はfirefoxsafariのみのようですが、 Rubyの配列展開(*)のようで面白いです。
Spread operator - JavaScript | MDN
 
ほかにも調べてみると Array.from() というのも実装されたようです。

Array.from(Array(3).keys())

Array.from() - JavaScript | MDN
 
しかし、MDNはドキュメントが充実していますなぁ。