---
type: reference
language: javascript
slug: array/sort
title: "Array.prototype.sort() と toSorted()"
title_tag: "JavaScript sort() — 比較関数・安定ソート・破壊的の扱い"
summary: >
  sort() は比較関数を渡さないと文字列として並べます。比較関数が返すべき値、真偽値を返すと
  並ばない理由、undefined と穴の位置、安定ソートの保証までを実行して確かめます。
description: >
  比較関数が真偽値を返すと、要素数によっては全く並びません。返すべき値、元を書き換える点、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: "String.prototype.localeCompare — MDN"
    url: "https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare"

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

links:
  related:
    - javascript/how-to/array/sort-numbers
    - javascript/reference/array/slice
    - javascript/learn/string/unicode

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

`sort()` は配列を並べ替えます。**[bad:元の配列を書き換え]、同じ配列を返します。**

```js run
const nums = [3, 1, 2];
const returned = nums.sort((a, b) => a - b);

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

戻り値は[key:新しい配列ではありません]。**元と同じものです。**

## 比較関数を渡さないと文字列になる

引数を省くと、要素を[fn:文字列に変えてから]並べます。

```js run
console.log([10, 9, 1, 100].sort());
console.log([10, 9, 1, 100].sort((a, b) => a - b));
```
```output
[ 1, 10, 100, 9 ]
[ 1, 9, 10, 100 ]
```

`'10' < '9'` なので、[num:10]が[num:9]より前に来ます。
**数値を並べるときは、必ず比較関数を渡してください。**

型が混ざっていても同じです。

```js run
console.log([true, false, null, 10, 'a'].sort());
```
```output
[ 10, 'a', false, null, true ]
```

`'10' < 'a' < 'false' < 'null' < 'true'` の順です。
**中身が何であれ、文字列として比べられます。**

→ [配列を数値の大きさで並び替える](/ja/javascript/how-to/array/sort-numbers/)

## 比較関数が返すべきもの

`compare(a, b)` は[key:数値]を返します。

| 戻り値 | 意味 |
|---|---|
| 負の数 | `a` を前に |
| [num:0] | 順番を変えない |
| 正の数 | `b` を前に |

だから `a - b` で昇順、`b - a` で降順になります。

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

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

常に[num:0]を返せば、**何も動きません。**

## 元を変えたくないなら

`toSorted()` は新しい配列を返します（ES2023）。

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

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

古い環境では、複製してから並べます。

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

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

[dim:`toSorted()` は Node 20 / Chrome 110 / Safari 16 より前では使えません。]

`reverse()` も同じく破壊的で、`toReversed()` が対になります。

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

console.log(nums.toReversed(), nums);
```
```output
[ 3, 2, 1 ] [ 1, 2, 3 ]
```

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

`sort()` は[type:安定ソート]です（ES2019 以降、仕様で保証されています）。
**比較で同じと判定された要素は、元の順番のままになります。**

```js run
const rows = [
  { name: 'A', group: 2 },
  { name: 'B', group: 1 },
  { name: 'C', group: 2 },
  { name: 'D', group: 1 },
];

console.log(rows.toSorted((x, y) => x.group - y.group).map((r) => r.name));
```
```output
[ 'B', 'D', 'A', 'C' ]
```

`group` が[num:1]の `B` と `D`、[num:2]の `A` と `C`。
**それぞれ元の並び順が保たれています。**

だから「まず名前順、次に点数順」のような並べ替えは、[key:逆の順に2回]かけても作れます。
ただし、1回で書くほうが読みやすくなります。

```js run
const rows = [
  { g: 2, n: 'b' }, { g: 1, n: 'z' }, { g: 2, n: 'a' }, { g: 1, n: 'y' },
];

console.log(rows.toSorted((x, y) => x.g - y.g || x.n.localeCompare(y.n)).map((r) => r.g + r.n));
```
```output
[ '1y', '1z', '2a', '2b' ]
```

`||` は[key:左が 0 のときだけ右を見ます]。**同点のときの2番目の基準**を、そのまま書けます。

## `undefined` と穴は必ず最後

```js run
console.log([3, undefined, 1].sort((a, b) => a - b));
console.log([3, , 1].sort());
```
```output
[ 1, 3, undefined ]
[ 1, 3, <1 empty item> ]
```

`undefined` は[bad:比較関数に渡されません]。無条件で末尾へ回されます。
[type:穴]はさらにその後ろです。

**比較関数の中で `undefined` を気にする必要はありません。** 来ないからです。

## よくある間違い

### 比較関数が真偽値を返している

```js bad
const nums = [5, 3, 9, 1, 7, 2, 8];

console.log(nums.sort((a, b) => a > b));
```
```output
[ 5, 3, 9, 1, 7, 2, 8 ]
```

**まったく並んでいません。**

`a > b` は `true` / `false` を返します。数値に直すと[num:1]と[num:0]で、
**「`b` を前に」と「変えない」しか表せません。**「`a` を前に」（負の数）が作れないので、並べ替えが成立しません。

[bad:要素数が少ないと、たまたま並ぶことがあります]。だから見逃されがちです。
`a - b` を使ってください。

### 文字列を `a - b` で比べる

```js bad
console.log(['い', 'あ', 'う'].sort((a, b) => a - b));
```
```output
[ 'い', 'あ', 'う' ]
```

文字列の引き算は `NaN` です。`NaN` は[num:0]と同じ扱いになるので、**何も起きません。**

文字列は既定の並べ替えか、`localeCompare()` を使います。

```js run
console.log(['い', 'あ', 'う'].sort());
console.log(['banana', 'Apple', 'cherry'].sort((a, b) => a.localeCompare(b, 'ja')));
```
```output
[ 'あ', 'い', 'う' ]
[ 'Apple', 'banana', 'cherry' ]
```

→ [文字を正しく数える](/ja/javascript/learn/string/unicode/)

### 並べ替えたつもりで元が変わっている

```js bad
const original = [3, 1, 2];
const sorted = original.sort((a, b) => a - b);

console.log(original);
```
```output
[ 1, 2, 3 ]
```

`sorted` を作ったつもりでも、`original` も並び替わっています。**同じ配列だからです。**
元を残したいなら `toSorted()` か `[...original].sort()` を使ってください。

## まとめ

- `sort()` は[bad:元を書き換える]。戻り値は同じ配列
- 比較関数を省くと**文字列として**並ぶ。数値には必ず渡す
- 比較関数は[key:数値]を返す。**真偽値では並ばない**
- `undefined` と[type:穴]は比較関数に渡されず、必ず末尾
- [type:安定ソート]が保証されている。**同点は元の順のまま**
- 元を残すなら `toSorted()` か `[...arr].sort()`
