【要約】[1, 10, 9, 2].sort() が [1, 10, 2, 9] を返した — JavaScriptのsortはデフォルトで数字を文字列として並べる [Qiita_Trend] | Summary by TechDistill
> Source: Qiita_Trend
Execute Primary Source
// Problem
開発者が数値配列をソートしようとした際、意図しない順序で結果が返ってくる問題に直面する。データ件数が少ないうちは正常に見えても、桁数が変化した瞬間にバグが表面化する。
- ・原因:
sort()は比較関数がない場合、要素を文字列に変換して辞書順で比較する。 - ・顕在化:1桁と2桁の数値が混在した際、10が2より前に来るなどの不整合が起きる。
- ・副作用:
sort()は元の配列を直接書き換える破壊的なメソッドである。 - ・影響:ReactのState管理などで、予期せぬ再レンダリングの失敗やバグを招く。
// Approach
JavaScriptの仕様に基づき、用途に応じた適切なソート手法を選択することで問題を解決する。単なる引き算だけでなく、型安全性や非破壊性を考慮した実装を行う。
- ・数値ソート:比較関数
(a, b) => a - bを渡し、数値の大小で比較させる。 - ・安全な比較:
NaNのリスクを避けるため、型チェックを含む比較関数を実装する。 - ・自然順ソート:
localeCompareのnumeric: trueオプションを用い、文字列内の数値を考慮する。 - ・非破壊操作:スプレッド構文によるコピー、またはES2023の
toSorted()を使用する。
// Result
適切な比較関数の利用と非破壊的な手法の採用により、ソートの正確性とコードの安全性が向上する。
- ・正確性:桁数が異なる数値も、期待通りの昇順・降順で並ぶ。
- ・安全性:元の配列が保持されるため、副作用による予期せぬバグを防止できる。
- ・運用改善:ESLintのルール導入により、比較関数の省略をCIで検知できる体制を構築できる。
Senior Engineer Insight
> 本件は「仕様を知らないことによるバグ」の典型例だ。特に、データ件数が少ないテスト環境では正常に動作し、本番環境でデータが増えた瞬間に崩れるという性質は、極めて検知が難しい。実務では、個人の注意に頼らず、ESLint等の静的解析ツールで比較関数の省略を強制すべきだ。また、副作用を避けるため、モダンな環境では
toSorted()を標準とするなど、チーム内でのコーディング規約の整備が不可欠である。