JavaScriptのオブジェクトのメモリの仕組み
JavaScriptはオブジェクトの変数をメモリに格納する場合は番地のみ格納する仕様になっています。なので、オブジェクトの中身をコピーしたい場合はシャローコピーやディープコピーなどの概念を理解する必要があります。
そもそもなぜオブジェクトは番地のみが格納されるのか?
オブジェクトは複数の値を保持することが普通なのでいちいち値を移していたら非常に時間がかかってしまうためです。なのでデフォルトではJSではオブジェクトは番地情報のみ変数に格納する仕様になっています。
シャローコピー
スプレット構文
なお、配列の操作であれば、concatでも同じようなことはできますが、基本的にスプレット構文の方が速いらしいので、スプレット構文を使った方が良さそうです。
例
1 2 3 |
const a = {a:1,b:2} const b = {c:3,d:4} const spread = {...a,...b} //{a: 1, b: 2, c: 3, d: 4} |
Object.assign
例
1 2 3 |
const a = {a:1,b:2} const b = {c:3,d:4} const assign = Object.assign({},a,b) //{a: 1, b: 2, c: 3, d: 4} |
シャローコピーの欠点
オブジェクトの2階層以降はメモリ位置のみのコピーになってしまう。
1 2 3 4 5 6 7 8 9 10 11 |
const a = {a:1,b:{b2:5}} const b = Object.assign({},a) b.a = 9 b.b.b2 = 7 console.log(a) { "a": 1, // こちらは書き換わらない。 "b": { "b2": 7 // 書き変わってしまう。 } } |
ディープコピー
JSON.parseとJSON.stringify
一度jsonに展開してまたオブジェクトに戻します。こうすればディープコピーを実現できます。
jsonでディープコピーする場合の落とし穴
一度jsonにする都合上、関数やundefinedが消滅してしまう。(関数という概念はjsonには存在しないため)
階層をつけてシャローコピーする。
1 2 3 4 5 6 7 |
const a = {a:1,b:{b2:5}} const b = { "a": 1, "b": { ...a.b } } |
こうすれば実質的にディープコピーになります。ただ、オブジェクトのプロパティが増えれば増えるほど冗長になるという欠点はあります。
その他
Reactなどではimmer.jsなどを使って簡単にイミュータブルな処理を実装してくれます。
ではなぜシャローコピーという概念があるのか?
ディープコピーに比べてコストがかからないためです。できるだけシャロコピーで済むものはシャロコピーで済ませるのが吉です。
この記事へのコメントはありません。