はじめに
オブジェクト同士の比較をするときに、「あ〜普通に等価演算子使えばいいじゃん」と思っていて思うような結果が返って来なかったことがありました。
オブジェクトの比較をどうするか、自分用メモです。
比較するオブジェクト
interface BaseObject {
id: number;
name: string;
language: string;
isWoman: boolean | null;
}
const objectA: BaseObject = {
id: 1,
name: "hoge",
language: "jpn",
isWoman: true,
};
const objectB: BaseObject = {
id: 1,
name: "hoge",
language: "jpn",
isWoman: true,
};
BaseObjectをベースとした二つのオブジェクトobjectAとobjectBを作ります。
この段階で、「はいはい同じオブジェクトね」と考えobjectA === objectBがtrue
であるものとして実装を進めていました。笑
なぜ同じじゃないのか
objectA === objectBがfalseになることはわかった、でもなんで?
見かけ上一緒じゃん!!と思っていた私。ではそもそもなぜ同じじゃないのか
objectAとobjectBは異なるアドレスを持っているから。
objectAはアメリカで作られているからアメリカの文化を持ってる。
逆にobjectBは日本で作られているから日本の文化を持っているイメージです。
なので、objectAとobjectBは表面上は一緒かもしれないけど、参照は違うって感じかな。と個人的なイメージですが。
参考サイトは図解されていてわかりやすいので、私のイメージ話は捨て去りこちらを参考にすると良いかもしれません。
比較演算子が使えない!じゃあどうやって比較する
JSONを使う
JSON.stringfy()で文字列にして比較する。
console.log(JSON.stringify(objectA) === JSON.stringify(objectB)); //true
ただ、JSON.stringfy()を使う場合はオブジェクトの中身の順序も同じでなければtrueにならない。
例えばobjectBのプロパティの順番を変えてみます。nameを一番上に、次にid がくるようなオブジェクトにします。
const objectA: BaseObject = {
id: 1,
name: "hoge",
language: "jpn",
isWoman: true,
};
const objectB: BaseObject = {
name: "hoge",
id: 1,
language: "jpn",
isWoman: true,
};
console.log(JSON.stringify(objectA) === JSON.stringify(objectB)); //false
配列以外のオブジェクトのプロパティでは、特定の順番で文字列化されることは保証されていません。文字列化された同じオブジェクトの中でプロパティの順番に依存しないようにしてください。MDN
同じ名前の同じ値のプロパティを持つオブジェクトであっても、異なる文字列に変換され得るということです。順番が異なっていたら、変換される文字列も異なります。
lodashのisEqualを使う
JSON.stringfy()で順番考えるのは手間ですし、機能的なバグも起こりやすくなるかと思います。
そこでlodashのisEqualを使う方法があります。
lodashはJavaScriptで使用されるユーテリティライブラリです。
ユーティリティライブラリとは「配列操作」「オブジェクト操作」「数値操作」といった様々な機能をまとめて提供しているライブラリのことです。
簡潔に言うとlodashには便利な関数がたくさんあるよってことです。
isEqualはオブジェクトのキー内の順序を考慮せずにオブジェクトが等いかどうかをチェックします。
_.isEqual(objectA, objectB);
// => true
objectA === objectB;
// => false
記述が少なくて済みますし、もっと安全かなと思います。実務ではこの方法を採用しました
使い方や導入方法は公式に記載されています。lodash