1. 作品 5 件を多い順に並べても元の先頭は変わらない
  2. 少ない順に並んだ配列を渡しても元は無傷
  3. 1 件だけなら並びは変わらない
  4. 空配列なら空の結果を返す
コース一覧
モダンJavaScript:データ処理とコード設計
sort と比較関数

モダンJavaScript:データ処理とコード設計

配列の map・filter・reduce・sort、クロージャと高階関数、オブジェクトとクラス、エラー設計、正規表現を学ぶ全 36 レッスン(665 分)のコースです。ローカルの作品データを題材に、表示とデータを分け、絞り込み・並び替え・入力検証までを組み立てます。Promise、fetch、API 通信、モジュールは次のコースで扱います。

1
土台をそろえる
01. このコースで育てるもの15分
02. strict mode が先に教えてくれる間違い15分
03. 表示とデータを切り分ける20分
04. 第1章まとめクイズ10分
2
配列をパイプラインで扱う
01. map で形を変える20分
02. filter と find で絞り込む20分
03. reduce でひとつにまとめる20分
04. sort と比較関数20分
05. 分類してまとめる groupBy20分
06. つなげて組み立てる20分
07. つくる 作品一覧の絞り込みと並び替え30分
08. 第2章まとめクイズ10分
3
関数を道具にする
01. クロージャで状態を閉じ込める20分
02. 設定を覚えた関数をつくる20分
03. 関数を返す関数20分
04. 副作用のない関数20分
05. 第3章まとめクイズ10分
4
オブジェクトを扱いきる
01. 分割代入で必要な値だけ取り出す20分
02. スプレッドとレストで組み替える20分
03. keys と values と entries20分
04. ビット演算でフラグをまとめる20分
05. 第4章まとめクイズ10分
5
クラスで型をつくる
01. クラスとインスタンス20分
02. private フィールドとアクセサ20分
03. 継承と super20分
04. 多態と static20分
05. つくる 作品コレクションをクラスにする30分
06. 第5章まとめクイズ10分
6
エラーを設計する
01. try catch finally20分
02. 自分でエラーを投げる20分
03. 失敗を画面に出す25分
04. 第6章まとめクイズ10分
7
正規表現
01. 正規表現のきほん20分
02. 入力を検証する20分
03. 置換とキャプチャ20分
04. 第7章まとめクイズ10分

sort と比較関数

比較関数が返す符号で並びが決まる
解説

このレッスンで分かること

  • sort は元の配列をその場で並べ替えます。複製してから呼ぶのが既定の書き方です
  • 比較関数を書かないと、数値でも文字列として比べられます

並べ替えたら、元の並びが二度と戻らない

map も filter も新しい配列を返しました。sort は違います。呼び出した配列そのものを並べ替え、同じ配列を返します。

JavaScript

const views = [120, 48, 200]; const sorted = views.sort((a, b) => b - a); console.log(sorted); // [200, 120, 48] console.log(views); // [200, 120, 48] 元も変わっている console.log(views === sorted); // true

sorted と views は同じ配列です。別の変数に入れたから安心、とはなりません。表示用に並べ替えたつもりで、元データの並びまで変わっています。並べ替えの結果を画面に出すだけなら、一見は困りません。困るのは、そのあとで「登録した順に戻したい」となったときです。元の順を取り戻す手段はもうありません。

対策は 1 つで、並べ替える前に複製します。

JavaScript

const sorted = [...views].sort((a, b) => b - a); // views は [120, 48, 200] のまま
書き方元の配列戻り値
list.sort(fn)並べ替わる同じ配列
[...list].sort(fn)変わらない新しい配列
list.slice().sort(fn)変わらない新しい配列

複製の 3 文字を惜しまないのが結局は早道です。なお filter のあとに sort をつなぐときは複製が要りません。filter がすでに新しい配列を返しているので、そこを並べ替えても元は無傷です。複製が必要なのは、元の配列に直接 sort を呼ぶときだけです。

比較関数を書かないと、数値が文字列で並ぶ

比較関数を省略すると、要素はいったん文字列に直されてから辞書順に並べられます。

JavaScript

const views = [120, 48, 200, 8, 32]; console.log([...views].sort()); // [120, 200, 32, 48, 8]

文字列として比べているので、先頭の文字が 1 の 120 が最初に来て、8 が最後に来ます。桁数がそろっていないほど結果はおかしくなります。要素が 1 桁だけのテストデータでは正しく見えるので、桁が増えて初めて気付きます。

数値として並べたいときは比較関数を渡します。引数を 2 つ受け取り、返した数値の正負で順番が決まります。負なら a を前に、正なら b を前に、0 なら順番を変えません。

JavaScript

[...views].sort((a, b) => a - b); // 昇順 [8, 32, 48, 120, 200] [...views].sort((a, b) => b - a); // 降順 [200, 120, 48, 32, 8]

a - b なら昇順、b - a なら降順、と形で覚えてしまって構いません。既定が文字列比較なのは、sort が数値以外の何が入っているか分からない配列も並べる必要があるからです。共通の物差しとして文字列を選んだ結果、数値の配列では意図しない並びになります。物差しは自分で渡すもの、と考えるとつじつまが合います。

オブジェクトの配列は、比べたい値を取り出す

要素がオブジェクトなら、比べたい項目を両側から取り出して引き算します。

JavaScript

const skills = [ { name: "CSS", years: 2 }, { name: "JavaScript", years: 5 } ]; const byExperience = [...skills].sort((a, b) => b.years - a.years);

文字列で並べたいときは引き算が使えません。日本語を含む文字列なら a.name.localeCompare(b.name) を使うと自然な順になります。真偽値もそのままでは引けないので、Number(...) で数値に直してから比べます。

よくある間違い

  • 比較関数で真偽値を返す — (a, b) => a > b は true と false しか返さず、数値に直すと 1 と 0 にしかなりません。負の値が出ないので、要素数が増えると並びが崩れます。必ず数値を返します
  • 戻り値だけを見て元が無事だと思い込む — 同じ関数を 2 回呼ぶと 1 回目と 2 回目で結果が変わり、原因の分からない不具合になります。関数の中で並べ替えるなら、引数として受け取った配列には触らないと決めてください

要件

  1. 関数名は sortByViewsDesc とし、引数は作品の配列 works を 1 つだけ受け取る
  2. 戻り値は titles と firstOriginal の 2 つのキーを持つオブジェクトにする
  3. titles は views の多い順に並べたタイトルの配列とし、published は条件に使わない
  4. firstOriginal は関数を抜ける時点での works の先頭のタイトルとし、works が空なら null にする

入出力例

sortByViewsDesc([{"id":1,"published":true,"tags":["HTML","CSS"],"title":"プロフィールサイト","views":120,"year":2026},{"id":2,"published":true,"tags":["HTML"],"title":"自己紹介カード","views":48,"year":2026},{"id":3,"published":true,"tags":["HTML","CSS"],"title":"スキル一覧の表","views":32,"year":2025},{"id":4,"published":false,"tags":["JavaScript"],"title":"作品ギャラリー","views":8,"year":2025},{"id":5,"published":true,"tags":["JavaScript"],"title":"学習ログ","views":200,"year":2024}]) → {"firstOriginal":"プロフィールサイト","titles":["学習ログ","プロフィールサイト","自己紹介カード","スキル一覧の表","作品ギャラリー"]} sortByViewsDesc([{"id":4,"published":false,"tags":["JavaScript"],"title":"作品ギャラリー","views":8,"year":2025},{"id":2,"published":true,"tags":["HTML"],"title":"自己紹介カード","views":48,"year":2026},{"id":1,"published":true,"tags":["HTML","CSS"],"title":"プロフィールサイト","views":120,"year":2026}]) → {"firstOriginal":"作品ギャラリー","titles":["プロフィールサイト","自己紹介カード","作品ギャラリー"]} sortByViewsDesc([{"id":3,"published":true,"tags":["HTML","CSS"],"title":"スキル一覧の表","views":32,"year":2025}]) → {"firstOriginal":"スキル一覧の表","titles":["スキル一覧の表"]} sortByViewsDesc([]) → {"firstOriginal":null,"titles":[]}

ヒント

並べ替える前にスプレッド構文で複製します。複製しないと works の並びまで変わり、firstOriginal がずれます。

比較関数は数値を返します。多い順にしたいので b.views - a.views と書きます。

firstOriginal は works が空のときに works[0] が undefined になります。length を先に見て null を返します。

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/03/27·更新 2026/08/26

関連レッスン

  • 分類してまとめる groupBy

    配列の要素をキーごとのまとまりに分ける書き方を学びます。reduce の初期値を空オブジェクトにして、年ごとに作品を束ねます。

  • つなげて組み立てる

    filter と sort と map を 1 本の流れにつないで表示用のデータを組み立てます。つなぐ順番で結果も計算量も変わることを確かめます。

  • つくる 作品一覧の絞り込みと並び替え

    この章で学んだ map と filter と reduce と sort と分類をすべて使い、作品一覧の表示データを 1 本の関数にまとめます。絞り込みの条件はオブジェクトで受け取ります。

  • 第2章まとめクイズ

    map と filter と find と reduce と sort の動きを、コードを読んで結果を答える形で確かめます。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • 配列サイズ固定の同型データの集まり
  • 関数処理に名前を付けて再利用できる単位
  • 変数データに名前をつけて参照する仕組み
  • 戻り値呼び出し元への返答を表す点線矢印
  • テストバグを見つける工程
  • 引数位置引数=順番で渡す。
  • オブジェクトキーと値のペアで構造を作るデータ
  • 素数1 と自分自身でしか割り切れない自然数
main.js
学習モード
エディタを読み込んでいます

メモ

sort と比較関数

⌘S で保存