---
type: why
language: javascript
slug: zero-index
title: "なぜ配列の番号は0から始まるのか"
title_tag: "なぜ配列の番号は0から始まるのか — 半開区間と距離で考える"
summary: >
  先頭からの距離を番号にしているからです。0 始まりだと slice の範囲、長さの計算、
  ループの条件がすべて足し算・引き算だけで揃います。1 始まりで書いたときのずれも確かめます。
description: >
  番号は「順番」ではなく「先頭からの距離」です。slice の範囲や length との関係が
  引き算だけで揃う理由と、最後の要素を取るときに 1 を引く理由を実行して確かめます。
status: published
difficulty: 1
minutes: 7

versions:
  verified: "Node 22.22.3"
  since: "ES1"
  deprecated: null
  removed: null

sources:
  - title: "Array Objects — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-array-objects"
  - title: "Array.prototype.slice — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-array.prototype.slice"
  - title: "E. W. Dijkstra, EWD831: Why numbering should start at zero"
    url: "https://www.cs.utexas.edu/~EWD/transcriptions/EWD08xx/EWD831.html"

terms: [添字, 半開区間, オフセット]

links:
  related:
    - javascript/learn/array/basics
    - javascript/reference/array/slice
    - javascript/how-to/array/chunk

content_updated_at: 2026-09-08
published_at: 2026-09-08
---

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

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

```js run
const fruits = ['あ', 'い', 'う'];

console.log(fruits[0]);
console.log(fruits[2]);
console.log(fruits.length);
```
```output
あ
う
3
```

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

## 0 始まりだと計算が揃う

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

```js run
const nums = [0, 1, 2, 3, 4];

console.log(nums.slice(0, 2));
console.log(nums.slice(2, 5));
console.log(nums.slice(0, 2).length);
console.log(nums.slice(2, 5).length);
```
```output
[ 0, 1 ]
[ 2, 3, 4 ]
2
3
```

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

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

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

```js run
const nums = [0, 1, 2, 3, 4];

console.log(nums.slice(0, 2));
console.log(nums.slice(2, 4));
console.log(nums.slice(4, 5));
```
```output
[ 0, 1 ]
[ 2, 3 ]
[ 4 ]
```

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

分割の処理が `i += size` だけで書けるのは、これが理由です。
→ [配列を決まった数ずつに分ける](/ja/javascript/how-to/array/chunk/)

### 繰り返しの条件も揃う

```js run
const fruits = ['あ', 'い', 'う'];

for (let i = 0; i < fruits.length; i++) {
  console.log(i, fruits[i]);
}
```
```output
0 あ
1 い
2 う
```

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

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

```js run
console.log(Array.from({ length: 3 }, (_, i) => i));
```
```output
[ 0, 1, 2 ]
```

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

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

```js bad
const fruits = ['あ', 'い', 'う'];

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

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

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

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

```js run
const fruits = ['あ', 'い', 'う'];

console.log(fruits[fruits.length - 1]);
console.log(fruits.at(-1));
```
```output
う
う
```

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

```js run
const fruits = ['あ', 'い', 'う'];

console.log(fruits.indexOf('あ'));
console.log(fruits.indexOf('無い'));
```
```output
0
-1
```

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

**`if (fruits.indexOf(x))` と書くと、先頭にあるときに `0` が偽と扱われます。**
→ [文字列を探す・分ける・置き換える](/ja/javascript/learn/string/search/)

## よくある誤解

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

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

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

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

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

```js run
const items = ['あ', 'い', 'う'];

items.forEach((item, i) => {
  console.log(`${i + 1}. ${item}`);
});
```
```output
1. あ
2. い
3. う
```

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

## 自分で確かめる

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

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

## まとめ

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