Edited at

TypeScriptでオブジェクトのシャローコピーとディープコピーの挙動を確かめた


やったこと

シャローコピーとディープコピーの挙動の理解がいまいちだったのでTypeScriptで試してみました。

ClassRoom型のmembersプロパティにUser型の配列が入っているような多次元のオブジェクトを以下の3パターンの方法でコピーした結果を比較しました。

・普通に代入

・locashのcloneDeepメソッドを利用

・スプレッド演算子を利用

・Object.assing


コード

// locashを読み込み

import * as lodash from 'lodash'
const _ = lodash

/**
* typeの定義
*/

type ClassRoom = {
name: string
members: User[]
}

type User = {
name: string
age: number
}

/**
* ClassRoom型とUser型のオブジェクトを定義
*/

let user1: User = {
name: 'Yorinton',
age: 18
}

let user2: User = {
name: 'ピーター・パン',
age: 15
}

let classroomA: ClassRoom = {
name: 'A',
members: [user1, user2]
}

/**
* 3パターンの方法で別変数にコピー
*/

// 普通に代入
let classroomB = classroomA
// lodashのcloneDeepを利用
let classroomC = _.cloneDeep(classroomA)
// スプレッド演算子
let classRoomD = { ...classroomA }
// Object.assign
let classRoomE = Object.assign(classroomA)

/**
* おおもとのオブジェクトの値を変更
*/

classroomA.name = 'B'
classroomA.members[1].name = 'ポーターピン'

/**
* 出力して結果を確認
*/

console.log(classroomA)
console.log(classroomB)
console.log(classroomC)
console.log(classRoomD)
console.log(classRoomE)


実行コマンド

$ npx ts-node ./src/copy.ts

※参照

https://qiita.com/Yorinton/items/28c46333e9d4f714e09c


結果

// classroomA (おおもとのオブジェクト)

{ name: 'B',
members: [ { name: 'Yorinton', age: 18 }, { name: 'ポーターピン', age: 15 } ] }

// classroomB (普通に代入) -> シャローコピーなので値が書き換わっている
{ name: 'B',
members: [ { name: 'Yorinton', age: 18 }, { name: 'ポーターピン', age: 15 } ] }

// classroomC (lodashのcloneDeep) -> ディープコピーなので値は書き換わっていない
{ name: 'A',
members: [ { name: 'Yorinton', age: 18 }, { name: 'ピーター・パン', age: 15 } ] }

// classroomD (スプレッド演算子) -> 1階層目のnameは書き換わっていない(ディープコピー)が、2階層目のnameは書き換わっている(シャローコピー)
{ name: 'A',
members: [ { name: 'Yorinton', age: 18 }, { name: 'ポーターピン', age: 15 } ] }

コピーの仕方で挙動が変わるので注意が必要。


※lodashインストール

lodashとTypeScript用に@types/lodashをinstall

$ npm install lodash

$ npm install @types/lodash