JavaScriptのsort()メソッドの落とし穴:片方をソートすると2つの配列が並び変わる問題と解決策
Array.prototype.sort()の特徴
JavaScriptのArray.prototype.sort()メソッドは「破壊的(in-place)」なソートアルゴリズムです。これは、ソート対象の配列のコピーを新たに作成せず、余分なメモリを使用せずに配列そのものを直接並べ替える方式です。この仕組みは効率性とパフォーマンスに優れている反面、思わぬ落とし穴につながることがあります。
問題の例
具体的な例で見てみましょう。文字列が格納されたnames配列があるとします。ここで、元の配列の順序はそのまま保持しつつ、同じ要素をアルファベット順にソートした別の配列を作りたいと考えます。
そこで、次のようなコードを書いたとします。
const names = ['Rakesh', 'Mukesh', 'Ram', 'Anshul', 'Dheeraj']; let sortedNames = names; sortedNames = sortedNames.sort(); console.log(names); console.log(sortedNames);
しかし、JavaScriptでは配列もオブジェクトの一種であり、オブジェクトは値ではなく参照渡しでコピーされます。そのため、一方の配列をソートすると、もう一方の配列まで一緒に並び替えられてしまうのです。これは明らかに意図した動作ではありません。
解決策
1. slice()を使って新しい配列を初期化する
const names = ['Rakesh', 'Mukesh', 'Ram', 'Anshul', 'Dheeraj']; let sortedNames = names.slice(); sortedNames = sortedNames.sort(); console.log(names); console.log(sortedNames);
slice()メソッドは、呼び出し元の配列の浅いコピー(shallow copy)を新しい配列として返します。引数を指定しない場合は、先頭から末尾までの全要素がコピーされます。
ただし、この方法は新しい配列の初期化が発生するぶん効率面ではやや劣り、さらに文字列や数値などのプリミティブ型の配列にしか効果がないという点に注意が必要です。次に紹介する方法はより効率的で、オブジェクトの配列にも対応できます。
2. JSON.stringify() / JSON.parse()を使う
const names = ['Rakesh', 'Mukesh', 'Ram', 'Anshul', 'Dheeraj']; let sortedNames = JSON.parse(JSON.stringify(names)); sortedNames = sortedNames.sort(); console.log(names); console.log(sortedNames);
配列を一度JSON文字列に変換してから再び配列に戻すことで、参照コピーではなく実体の複製を作ることを強制できます。これにより、元の配列と完全に独立した新しい配列が得られます。
補足:toSorted()メソッド(ES2023以降)
なお、ES2023で導入されたArray.prototype.toSorted()を使えば、元の配列を一切変更せずに、ソート済みの新しい配列を直接取得できます。モダンな実行環境では、これが最もシンプルで安全な解決策となります。
const names = ['Rakesh', 'Mukesh', 'Ram', 'Anshul', 'Dheeraj']; const sortedNames = names.toSorted(); console.log(names); console.log(sortedNames);
実行結果
slice()およびJSON.parse(JSON.stringify())のどちらの方法でも、コンソールへの出力は同じになります。
[ 'Rakesh', 'Mukesh', 'Ram', 'Anshul', 'Dheeraj' ] [ 'Anshul', 'Dheeraj', 'Mukesh', 'Rakesh', 'Ram' ]
元のnames配列は元の順序を保ったまま、sortedNamesだけがアルファベット順に並び替えられていることが確認できます。配列を扱う際は、参照共有による意図しない副作用に常に注意しましょう。
-
JavaScriptのsort()メソッドとは?配列ソートの基本と比較関数の使い方を解説
JavaScriptのsort()メソッドは、配列の要素を並べ替えるための組み込みメソッドです。アルファベット順・数値順といった並べ替えの基準に加え、昇順・降順も自由に指定できます。デフォルトでは要素が文字列として比較され昇順にソートされますが、比較関数を渡すことで任意の順序を実現できます。 なお、sort()は元の配列そのものを変更する「破壊的メソッド」である点にも注意しましょう。元の配列を保持したい場合は、スプレッド構文([...arr])などで事前にコピーしておくのが安全です。 コード例 以下は、sort()メソッドを使って配列をソートするシンプルなサンプルコードです。 <!DO
-
【JavaScript】2つの配列を1つのオブジェクトに変換する方法をわかりやすく解説
2つの配列を1つのJavaScriptオブジェクトに変換できる? はい、可能です。JavaScriptでは「キー」となる配列と「値」となる配列の2つを組み合わせて、1つのオブジェクトを作成できます。最も基本的な方法は、forEach()メソッドで片方の配列をループ処理しながら、もう片方の配列の対応する要素を値として代入していくやり方です。 以下に、実際に動作するサンプルコードを紹介します。 コード例 <!DOCTYPE html> <html lang=ja> <head> <meta charset=UTF-8 /> <meta name