オブジェクトのコピー、マージについて取り上げます。「shallow copy」「deep copy」などの違いを意識して実装する必要があります。
(動作検証はTypescriptで行っています。)
目次
コピー
修正前|Objectは参照渡し
Objectは参照渡しになります。そのため、以下のように change関数
で変更した内容が objectA
にも反映されます。
const output = (obj: {}) => {
console.log(JSON.stringify(obj, null, 2));
};
const change = (obj: any) => {
obj['xxx'] = 1;
};
const objectA = {
aaa: 10,
bbb: 5,
};
output(objectA);
// {
// "aaa": 10,
// "bbb": 5
// }
change(objectA);
output(objectA);
// {
// "aaa": 10,
// "bbb": 5,
// "xxx": 1
// }
修正方法1|Object.assignでコピー
Object.assign
を利用すると、Objectのコピーを作ることができます。
const output = (obj: {}) => {
console.log(JSON.stringify(obj, null, 2));
};
const change = (obj: any) => {
obj['xxx'] = 1;
};
const objectA = {
aaa: 10,
bbb: 5,
};
output(objectA);
// {
// "aaa": 10,
// "bbb": 5
// }
change(Object.assign({}, objectA));
output(objectA);
// {
// "aaa": 10,
// "bbb": 5,
// }
change関数
内ではコピーした別の実体を変更しています。そのため objectA
自体に変化が生じなくなりました。
修正方法2|スプレッド構文を利用
以下のようにスプレッド構文を利用して対応することも可能です。
const output = (obj: {}) => {
console.log(JSON.stringify(obj, null, 2));
};
const change = (obj: any) => {
obj['xxx'] = 1;
};
const objectA = {
aaa: 10,
bbb: 5,
};
output(objectA);
// {
// "aaa": 10,
// "bbb": 5
// }
change({ ...objectA });
output(objectA);
// {
// "aaa": 10,
// "bbb": 5,
// }
Object.assignでマージ
Object.assign
は第1引数のオブジェクトに第2引数以降のオブジェクトをマージするといった処理を行っています。
(コピーを作成したい場合は 空のオブジェクト
を第1引数に指定します。)
第1引数のオブジェクトに第2引数のオブジェクトをマージしてみます。
const output = (obj: object) => {
console.log(JSON.stringify(obj, null, 2));
};
const objectA = {
aaa: 10,
bbb: 5,
};
const objectB = {
aaa: 20,
ccc: 3,
};
output(Object.assign(objectA, objectB));
// {
// "aaa": 20,
// "bbb": 5,
// "ccc": 3
// }
output(objectA);
// {
// "aaa": 20,
// "bbb": 5,
// "ccc": 3
// }
output(objectB);
// {
// "aaa": 20,
// "ccc": 3
// }
shallow copyとdeep copy
shallow copy
Object.assign
を利用したコピーでは第1階層までしかコピーしてくれません。
const output = (obj: {}) => {
console.log(JSON.stringify(obj, null, 2));
};
const change1 = (obj: any) => {
obj['x'] = 'change';
};
const change2 = (obj: any) => {
obj['x']['xx'] = 'change';
};
const objectA = {
x: {
xx: 1,
yy: 2,
},
};
output(objectA);
// {
// "x": {
// "xx": 1,
// "yy": 2
// }
// }
change1(Object.assign({}, objectA));
output(objectA);
// {
// "x": {
// "xx": 1,
// "yy": 2
// }
// }
change2(Object.assign({}, objectA));
output(objectA);
// {
// "x": {
// "xx": "change",
// "yx": 2
// }
// }
objectA['x']['xx']
の値が change
に変わってしまいました。
deep copy
解決方法の1つとして lodash
の cloneDeep
を利用するという方法があります。
import * as lodash from 'lodash';
const output = (obj: {}) => {
console.log(JSON.stringify(obj, null, 2));
};
const change1 = (obj: any) => {
obj['x'] = 'change';
};
const change2 = (obj: any) => {
obj['x']['xx'] = 'change';
};
const objectA = {
x: {
xx: 1,
yy: 2,
},
};
output(objectA);
// {
// "x": {
// "xx": 1,
// "yy": 2
// }
// }
change1(lodash.cloneDeep(objectA));
output(objectA);
// {
// "x": {
// "xx": 1,
// "yy": 2
// }
// }
change2(lodash.cloneDeep(objectA));
output(objectA);
// {
// "x": {
// "xx": 1,
// "yx": 2
// }
// }