JavaScriptにおけるシャローコピーとディープコピーについて
JavaScriptにおけるシャローコピー(shallow copy)とディープコピー(deep copy)について簡単にまとめました。 shallowは日本語で「浅い」という意味になります。
シャローコピー
シャローコピーはざっくり言うと参照元のオブジェクトとコピー先のオブジェクトどちらも同じメモリを参照していることをいいます。
簡単な例
const obj = { name: "hoge", age: 24 } const obj2 = obj obj.name = "fuga"; console.log(obj2.name) // fuga console.log(obj.name) // fuga
同じメモリを参照しているのでobj2
のname
を変更するobj
のname
も変更されてしまいます。
ディープコピー
ディープコピーとは、オブジェクトのみのコピーではなく、オブジェクトとメモリ上のデータの両方をコピーします。コピー元のプロパティを変更しても、コピー先のプロパティは変更されません。
スプレッド演算子を使ってディープコピーをしてみたいと思います。
const newObj = { ...obj } newObj.name = "taro" console.log(newObj.name) // taro console.log(obj.name) // hoge
ちゃんとできているように見えます。
では次のケースはどうでしょうか? familiesプロパティのオブジェクトを追加しました。
const obj = { name: "hoge", age: 24, families: { brothers: 3, sisters: 1 } } const newObj = { ...obj } newObj.families.brothers = 5 console.log(newObj.families.brothers) // 5 console.log(obj.families.brothers) // 5
コピー元とコピー先のプロパティどちらも変更されてしまっています。 スプレッド演算子はシャローコピーだということがわかります。
JSON.stringifyとJSON.parseを使う方法があるそうですが、undefinedや関数が定義されていると、プロパティがなくなってしまうのです。 下の例をみてください。
const person = { name: "二郎", age: 20, run: () => {console.log("すとすと")} } person2 = JSON.parse(JSON.stringify(person)) console.log(person2) // {name: "二郎", age: 20}
関数runがありません・・・
もっと簡単な方法はないかと思っていたところ、ありました。 lodashを使用する方法です。
const _ = require('lodash'); // 追加 const obj = { name: "hoge", age: 24, families: { brothers: 3, sisters: 1 }, run: () => {console.log("すとすと")} } const newObj = _.cloneDeep(obj) console.log(newObj); // { name: 'hoge', age: 24, family: { brother: 2, sister: 1}, run: [Function: run] } newObj.families.brothers = 10000; console.log(newObj.families.brothers); // 1000 console.log(obj.families.brothers); // 3
ちゃんとディープコピーができています。 これからもlodashとは仲良くしていきたいと思います。
簡単ではありますが、JavaScriptにおけるシャローコピー、ディープコピーについて紹介しました。