---
type: how-to
language: javascript
slug: array/sort-numbers
title: "配列を数値の大きさで並び替える"
title_tag: "JavaScript 配列の並び替え — sort で数値が狂う理由と直し方"
summary: >
  sort() は既定で文字列として比べるため、数値を渡すと [1, 10, 2] のように並びます。
  比較関数の書き方、元の配列を壊さない方法、日本語やオブジェクトの並び替えまでまとめます。
description: >
  sort() は比較関数を省くと文字列として並べるため、10 が 9 より前に来ます。昇順・降順の書き方、元の配列が変わる点、undefined が必ず末尾に行く挙動まで示します。
status: published
difficulty: 2
minutes: 9

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

sources:
  - title: "Array.prototype.sort — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-array.prototype.sort"
  - title: "Array.prototype.toSorted — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-array.prototype.tosorted"
  - title: "Array.prototype.sort() — MDN"
    url: "https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort"

terms: [比較関数, 破壊的メソッド, 安定ソート]

links:
  related:
    - javascript/learn/array/basics
    - javascript/reference/array/map
    - javascript/reference/array/sort

content_updated_at: 2026-09-07
published_at: 2026-09-07
---

## 答え

**比較関数を渡します。** そして[key:元の配列を壊さない]ように、先に複製します。

```js run
const nums = [10, 1, 5, 100, 2];

const asc = [...nums].sort((a, b) => a - b);

console.log(asc);
console.log(nums);
```
```output
[ 1, 2, 5, 10, 100 ]
[ 10, 1, 5, 100, 2 ]
```

降順は `b - a` です。

```js run
const nums = [10, 1, 5, 100, 2];

console.log([...nums].sort((a, b) => b - a));
```
```output
[ 100, 10, 5, 2, 1 ]
```

## なぜそのまま並べると狂うのか

`sort()` は、比較関数を渡さないと[bad:全部を文字列に変換してから]比べます。

```js bad
const nums = [10, 1, 5, 100, 2];

console.log(nums.sort());
```
```output
[ 1, 10, 100, 2, 5 ]
```

文字列として並べると `'10'` は `'2'` より前になります。
[num:1]文字目の `'1'` と `'2'` を比べているからです。**辞書順です。**

仕様にもそう書いてあります。比較関数が `undefined` のとき、
要素を文字列に変換してから比べる、と定められています。

## 比較関数の決まり

比較関数は[num:2]つの値を受け取り、**数値を返します。**

| 返す値 | 意味 |
|---|---|
| 負の数 | `a` を[em:前]にする |
| `0` | 順序を[em:変えない] |
| 正の数 | `a` を[em:後ろ]にする |

`a - b` が昇順になるのは、`a` のほうが小さいときに[key:負の数]になるからです。

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

console.log(nums.map(n => n).sort((a, b) => {
  console.log(`${a} と ${b} を比べる → ${a - b}`);
  return a - b;
}));
```
```output
1 と 3 を比べる → -2
2 と 1 を比べる → 1
2 と 3 を比べる → -1
2 と 1 を比べる → 1
[ 1, 2, 3 ]
```

[num:3]件なのに[num:4]回比べています。同じ組を[em:2回]見てもいます。

**どの順で何回比べるかは、仕様で決まっていません。** 処理系に任されています。
比較関数は[key:いつどう呼ばれても同じ答えを返す]ように書いてください。
中で数を数えたり、外の変数を書き換えたりすると[bad:結果が読めなくなります]。

**真偽値を返してはいけません。** `(a, b) => a > b` は `true` / `false` になり、
数値に直すと `1` / `0` です。[bad:「前にする」を表せません]。

## 元の配列を壊さない

`sort()` は[type:破壊的メソッド]です。**呼んだ配列そのものを並び替えます。**

```js bad
const nums = [3, 1, 2];

const sorted = nums.sort((a, b) => a - b);

console.log(sorted);
console.log(nums);
console.log(sorted === nums);
```
```output
[ 1, 2, 3 ]
[ 1, 2, 3 ]
true
```

戻り値は[key:同じ配列]です。別物ではありません。
元を残したいなら、次のどちらかにします。

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

console.log([...nums].sort((a, b) => a - b));
console.log(nums.toSorted((a, b) => a - b));
console.log(nums);
```
```output
[ 1, 2, 3 ]
[ 1, 2, 3 ]
[ 3, 1, 2 ]
```

`toSorted()` は[key:新しい配列を返す]書き方です（ES2023）。
[dim:Node 20 / Chrome 110 / Safari 16 より前の環境では使えません。迷ったら、スプレッド構文で複製してから `sort()` を呼ぶほうが確実です。]

## 文字列を並び替える

英数字だけなら比較関数は要りません。既定の辞書順で並びます。

```js run
const words = ['banana', 'apple', 'cherry'];

console.log([...words].sort());
```
```output
[ 'apple', 'banana', 'cherry' ]
```

**日本語では期待どおりになりません。** 文字コード順に並ぶためです。

```js run
const names = ['さとう', 'あおき', 'たなか', 'ざっそう'];

console.log([...names].sort());
console.log([...names].sort((a, b) => a.localeCompare(b, 'ja')));
```
```output
[ 'あおき', 'さとう', 'ざっそう', 'たなか' ]
[ 'あおき', 'ざっそう', 'さとう', 'たなか' ]
```

「さとう」と「ざっそう」の順が[key:入れ替わります]。

- 既定 … `さ`（U+3055）と `ざ`（U+3056）を[bad:別の文字]として比べるので、
  [num:1]文字目で決まってしまう
- `localeCompare` … `ざ` を `さ` の[em:濁った形]として扱うので、
  [num:2]文字目の `っ` と `と` で決まる。**国語辞典と同じ並び**

濁点・半角と全角・大文字と小文字が混ざると、こうした差が出ます。
**日本語を並べるときは `localeCompare` を使ってください。**

```js run
const words = ['B', 'a', 'C', 'b'];

console.log([...words].sort());
console.log([...words].sort((a, b) => a.localeCompare(b, 'ja')));
```
```output
[ 'B', 'C', 'a', 'b' ]
[ 'a', 'b', 'B', 'C' ]
```

既定では[bad:大文字が全部先に来ます]。ASCII では大文字（65〜）が小文字（97〜）より小さいためです。
`localeCompare` なら[key:文字として同じもの]をまとめ、`a` `b` `B` `C` の順になります。

## オブジェクトの配列を並び替える

比べたい値を取り出して、同じように書きます。

```js run
const users = [
  { name: 'あかり', age: 30 },
  { name: 'ゆうと', age: 22 },
  { name: 'はると', age: 41 },
];

const byAge = [...users].sort((a, b) => a.age - b.age);

console.log(byAge.map(u => `${u.name}(${u.age})`));
```
```output
[ 'ゆうと(22)', 'あかり(30)', 'はると(41)' ]
```

名前で並べるなら `localeCompare` です。

```js run
const users = [
  { name: 'ゆうと' },
  { name: 'あかり' },
];

console.log([...users].sort((a, b) => a.name.localeCompare(b.name, 'ja')).map(u => u.name));
```
```output
[ 'あかり', 'ゆうと' ]
```

## 同じ値の順序は保たれる

比較関数が `0` を返した組は、[key:元の並び順のまま]です（[type:安定ソート]。ES2019 以降は仕様で保証）。

```js run
const items = [
  { key: 'b', n: 1 },
  { key: 'a', n: 2 },
  { key: 'a', n: 3 },
];

console.log([...items].sort((x, y) => x.key.localeCompare(y.key)).map(i => i.key + i.n));
```
```output
[ 'a2', 'a3', 'b1' ]
```

`a2` と `a3` の順序が入れ替わりません。**2段階で並べたいときに使えます**
（先に第2キーで並べ、次に第1キーで並べる）。

## undefined は必ず最後に行く

`undefined` は比較関数に[bad:渡されません]。問答無用で末尾に置かれます。

```js run
const nums = [3, undefined, 1];

console.log([...nums].sort((a, b) => a - b));
```
```output
[ 1, 3, undefined ]
```

一方 `NaN` は渡されます。`NaN` との引き算は `NaN` になり、
比較関数が数値を返さないので[bad:並びが定まりません]。

```js bad
const nums = [3, NaN, 1, 2];

console.log([...nums].sort((a, b) => a - b));
```
```output
[ 3, NaN, 1, 2 ]
```

**並び替える前に弾いてください。**

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

const clean = nums.filter(n => !Number.isNaN(n));

console.log([...clean].sort((a, b) => a - b));
```
```output
[ 1, 2, 3 ]
```

`NaN` の比較については
[なぜ NaN === NaN は false なのか](/ja/javascript/why/nan-equality/) にまとめてあります。

比較関数の決まり、安定ソートの保証、`undefined` の扱いは用語のページにまとめてあります。
→ [Array.prototype.sort() と toSorted()](/ja/javascript/reference/array/sort/)
