なぜ配列の番号は0から始まるのか

先頭からの距離を番号にしているからです。0 始まりだと slice の範囲、長さの計算、ループの条件がすべて足し算・引き算だけで揃います。1 始まりで書いたときのずれも確かめます。

実行して検証済み処理系Node 22.22.3対応ES1難易度○○○○目安7更新

番号は「何番目か」ではなく、先頭からどれだけ離れているかだからです。

先頭は先頭から0だけ離れています。だから0です。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
あ う 3
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 0, 1 ] [ 2, 3, 4 ] 2 3

最後の番号は length - 1 になります。長さと最後の番号がずれるのは、 「距離」と「個数」が別のものだからです。

0 始まりだと計算が揃う

いちばん分かりやすいのは、範囲を切り出すときです。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 0, 1 ] [ 2, 3 ] [ 4 ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
0 あ 1 い 2 う

取れる個数は、いつでも 終わり - 始まり です。 2 - 0 で2個、5 - 2 で3個。例外がありません。

slice(start, end)end を含めない書き方を半開区間と呼びます。 0 始まりと半開区間は組で働きます。

隣り合う範囲が、そのまま繋がる

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 0, 1, 2 ]
javascript
const fruits = ['あ', 'い', 'う'];

console.log(fruits[1]);
console.log(fruits[fruits.length]);
い undefined

前の終わりが、次の始まりになっています。 重なりも隙間もありません。

分割の処理が i += size だけで書けるのは、これが理由です。 → 配列を決まった数ずつに分ける

繰り返しの条件も揃う

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
う う
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
0 -1

i < length で、ちょうど length 回まわります。 <= にすると1回多く回り、最後は undefined になります。

連番を作るときも同じです。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
1. あ 2. い 3. う

個数を渡すと、そのまま番号が並びます。

1 始まりだと思うと、どこがずれるか

  • 1番目のつもりで [1] を読むと、2番目が返ります
  • 最後のつもりで [length] を読むと、範囲の外なので undefined

どちらもエラーになりません。 静かに1つずれます。

最後の要素は length - 1 です。at(-1) のほうが読みやすくなります。

見つからないときが -1 なのも同じ理由

0 は「先頭で見つかった」という正しい答えです。 だから「無い」には、番号としてありえない -1 を使います。

if (fruits.indexOf(x)) と書くと、先頭にあるときに 0 が偽と扱われます。文字列を探す・分ける・置き換える

よくある誤解

「0 始まりは分かりにくいだけの慣習」

計算が揃うという実利があります。 上で見たとおり、 個数・範囲・繰り返しの条件が、すべて足し算と引き算だけで書けます。

1 始まりにすると、範囲の指定でどこかに +1-1 が必要になります。 この論点は 1982 年の E. W. Dijkstra の覚書(EWD831)で整理されています。出典は下に置いてあります。

「人に見せるときも 0 から数える」

それは別の話です。 画面に出す番号は i + 1 にしてください。

内部の番号と、人に見せる番号は分けます。

自分で確かめる

上のコードは書き換えて実行できます。

  1. for の条件を i <= fruits.length にして、何が出るか見る
  2. slice(1, 1) の結果と長さを見る(1 - 1 で0個)
  3. fruits[-1]fruits.at(-1) を並べる

まとめ

  • 番号は「順番」ではなく先頭からの距離
  • 取れる個数は、いつでも 終わり - 始まり例外が無い
  • 隣の範囲がそのまま繋がる(半開区間
  • 最後は length - 1。読みやすさなら at(-1)
  • -1 が「無い」なのは、0正しい答えだから
  • 人に見せる番号は i + 1 内部の番号と分ける

この記事の根拠

  1. Array Objects — ECMAScript® 2026 Language Specificationtc39.es
  2. Array.prototype.slice — ECMAScript® 2026 Language Specificationtc39.es
  3. E. W. Dijkstra, EWD831: Why numbering should start at zerowww.cs.utexas.edu

掲載しているコード例は、公開前に読み手が押したときに動くのと同じもので実行して出力を突き合わせています。結果はリポジトリに残しています。

このページの原文(Markdown)