JavaScriptの配列の等価性について
予想外の結果
JavaScriptで配列を比較すると、直感に反する結果が返ってきます。
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(arr1 === arr2); // false(なぜ?)
内容が完全に同じなのに、なぜfalseになるのでしょうか。
参照型と値型の違い
JavaScriptのデータ型は、大きく2つに分類されます。
値型の比較
値型は値そのものを比較します。
const num1 = 10;
const num2 = 10;
console.log(num1 === num2); // true(値が同じ)
const str1 = "hello";
const str2 = "hello";
console.log(str1 === str2); // true(値が同じ)
参照型の比較
配列やオブジェクトなどの参照型は、値ではなく参照先を比較します。
メモリ上での配列の扱い
配列を作成すると、JavaScriptはメモリ上に配列のデータを保存し、変数にはそのメモリアドレスが格納されます。
たとえ内容が同じでも、arr1とarr2は異なるメモリアドレスを参照しているため、===で比較するとfalseになります。
なぜ===がfalseになるのか
===演算子は、参照型の場合「同じメモリアドレスを指しているか」を比較します。
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
const arr3 = arr1; // arr1と同じ参照をコピー
console.log(arr1 === arr2); // false(異なる参照)
console.log(arr1 === arr3); // true(同じ参照)
配列の内容を比較する方法
では、配列の内容が同じかどうかを確認したい場合はどうすればよいでしょうか。
方法1: JSON.stringifyを使う
配列を文字列に変換してから比較します。シンプルな配列には有効ですが、ネストしたオブジェクトや順序が異なる場合には注意が必要です。
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(JSON.stringify(arr1) === JSON.stringify(arr2)); // true
方法2: 要素を一つずつ比較
長さを確認した後、全ての要素を比較します。
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
function arraysEqual(a, b) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
console.log(arraysEqual(arr1, arr2)); // true
方法3: everyメソッドを使う
より簡潔に書くことができます。
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
function arraysEqual(a, b) {
return a.length === b.length && a.every((value, index) => value === b[index]);
}
console.log(arraysEqual(arr1, arr2)); // true
方法4: ライブラリを使う
Lodashなどのライブラリを使うと、より複雑な比較も簡単に行えます。
// Lodashを使用
const _ = require('lodash');
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(_.isEqual(arr1, arr2)); // true
まとめ
JavaScriptの配列比較では、以下のポイントを押さえておきましょう。
- 配列は参照型なので、===は参照先のメモリアドレスを比較する
- 内容が同じでも、異なる配列として作成された場合は===でfalseになる
- 配列の内容を比較したい場合は、専用の比較関数を用意する必要がある
この仕組みを理解しておくことで、予期せぬバグを防ぐことができます。