KAEDE Hack blog

JavaScript 中心に ライブラリなどの使い方を解説する技術ブログ。

JavaScript Object の === による比較では中身は比較されないので JSON.stringify() して比較する

object の中身が比較で見られていないことを確認する

=== で同じ内容の object が true にならなかった

object の比較をして、うまくいかなかった

const dog = {
  name: 1,
  age: 5,
}
const dog2 = {
  name: 1,
  age: 5,
}
console.log(dog === dog2);

これが 中身のプロパティは同じなのに false になる

同じ中身を持つ違う名前の object を === で比較できない。

同一参照のみ === で true になることを確認

www.deep-rain.com

同一参照、同じメモリ?同じものを参照している物の場合のみ === が効くようだ。

しかし、ハードリンクのように、全く同じものを参照しているかどうかを

JS の === は判定しているわけではない。

const dog = {
  name: 1,
  age: 5,
}
const dog2 = dog
console.log(dog === dog2);
dog2.name = 2
console.log(dog === dog2);

これは2つとも true になる。

dog を元に dog2 を定義しているこのコードでは、dog2 の中身のプロパティが変わっているにも関わらず、2回目の比較すらも true になってしまう。

なので Object の === は、中身を見ているわけでは全くない。

作られた時のリンクを見ていると推測する。

だから中身が書き換わっても、最後の比較では true が返る。

まとめ

JS の obj を === で比較しても中身を比較はしてくれない。

これが比較してくれるのは、作成時に片方からもう片方が作られているかだけだ。

なので obj の中身を見たければ中身を展開して比較する必要がある。

object の中身を === 以外の手法で比較してみる

JSON.stringify() を使って object を string にする

ストリンギファイ

developer.mozilla.org

object などを JSON の形の文字列にするメソッド。

const dog = {
  name: 1,
  age: 5,
}
const jsonDog = JSON.stringify(dog)
console.log(jsonDog);

例えばこの dog object を JSON.stringify() すると

{"name":1,"age":5}

この結果が返ってくる。

console.log(typeof(jsonDog));

typeof で type を見ると

string

文字列になっている

console.log(typeof(dog));

一方、最初の dog の type を見てみると

 object
{"name":1,"age":5}

object になっている。

stringify() で string にした物を比較してみる

const dog = {
  name: 1,
  age: 5,
}
const dog2 = {
  name: 1,
  age: 5,
}
console.log(dog === dog2);

const stringDog = JSON.stringify(dog)
const stringDog2 = JSON.stringify(dog2)
console.log(stringDog === stringDog2);

前者の dog, dog2 は前述の通り別の生成をされた object なので false になるが

後者の stringDog, stringDog2 は文字列にされた上で、文字列として比較されているので true になる。簡単な object ならこれで比較できるようだ。

階層を深くして比較してみる

const dog = {
  name: 1,
  age: 5,
  child: {
    grandChild: {
      name: 100
    }
  }
}
const dog2 = {
  name: 1,
  age: 5,
  child: {
    grandChild: {
      name: 100
    }
  }
}

子、孫まで階層を追加したが、これでも stringify して比較すれば true かどうか判断できた。

順序を逆にして比較してみる

const dog = {
  name: 1,
  age: 5,
}
const dog2 = {
  age: 5,
  name: 1,
}
const stringDog = JSON.stringify(dog)
const stringDog2 = JSON.stringify(dog2)
console.log(stringDog); // {"name":1,"age":5}

console.log(stringDog2);// {"age":5,"name":1}
console.log(stringDog === stringDog2); // false

// のコメントの後の結果の通り、順番を入れるだけで、この方法は成立しなくなってしまう。中身が同じなのにも関わらず。

まとめ

object そのものは === では中身が同じかどうかみることができない。

しかし JSON.stringify(object) して string にしてしまえば二つの object の中身が同じかどうか確認することは可能。

ただ、プロパティの順番が変わるだけで別の文字列になってしまうので自作ソートを実装する必要がある。

まだある問題点

Object はブラウザ間の差異、Safari で結果が違うらしい。それも考慮して実装する必要がある。