LoginSignup
30
20

More than 3 years have passed since last update.

JavaScriptでrange関数作ってみた

Last updated at Posted at 2019-04-08

要件

  • 関数名はrangeとする
  • 数値型の引数を2つ(start, end)受け取る
  • startから始まりendで終わる整数値の連番を配列で返す
const list = range(2, 5);
console.log(list);
[2,3,4,5]

実装

forで回す

const range = (start, end) => {
  const list = [];
  for (let i = start; i <= end; i++ ) {
    list.push(i);
  }
  return list;
}

Array.fromを使う

MDNのサンプルコードを参考に

const range = (start, stop) => Array.from({ length: (stop - start) + 1}, (_, i) => start + i);

スプレッド構文を使う

  • 一番短く書けて、実行も早かった
const range = (start, end) => [...Array(end + 1).keys()].slice(start);

やっていること
1. Array(end + 1) => end + 1の長さの配列を作成。MDN:Arrayコンストラクタ
2. .key() => 作った配列のindexを返すArray Iteratorを作成。MDN:Array.prototype.keys()

3. [...Array(end + 1).keys()] => スプレッド構文でiteratorを配列に変換する。MDN:スプレッド構文
4. .slice(start) => 0からの連番になっているので、sliceを使ってstart番目から始まる配列のコピーを作成。MDN:Array.prototype.slice()

一言

keys()phpのarray_keysと同じで配列返すと思っていたのでArray(end + 1).keys().slice(start)でもいけるのでは?と思った。
戻り値イテレータだった。sliceは配列なのに・・・

スプレッド構文を使う(改良版)

コメントにてパフォーマンス面で無駄があること指摘していただいたので改良しました。
ひとつ前のsliceでカットする方法だと、startが大きくなった時に無駄に配列を確保することになるので直しました。

const range = (start, end) => [...Array((end - start) + 1)].map((_, i) => start + i);

おまけ(計測)

実行環境

Google Chrome
バージョン: 75.0.3770.142(Official Build) (64 ビット)

計測結果

※実行する環境によって実行速度やパフォーマンスの優劣は異なります。
 自身の環境でお試しください。

方法 実行時間 平均(30回)
forで回す 338~430ms(初回呼び出し) 37ms
20~30ms(2回目以降) -
Array.fromを使う 173~260ms 192ms
スプレッド構文+slice 61~105ms 121ms
スプレッド構文+map 35~60ms 44ms

See the Pen rangeいろいろ by r-kojima (@RyutaKojima) on CodePen.

一言

Chromeではforで回す方法が、初回は時間がかかるけど2回目以降の呼び出しがすごく早かった。
最適化がかかるのか、検証コードが間違っているのか、理由はよくわかりませんでした。

30
20
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
20