概要
Object.assign() を用いてイミュータブルな変更を行う。
ミュータブル(mutable)な変更
例えば、太郎君の毎日の献立が、以下のようになっているとします。
const gohan = { morning:"パン", lunch:"カレー", dinner:"ラーメン" }
これだと炭水化物のメニューばかりなので、夕食はサラダにする別の献立を考えました。
その際、毎日の献立を元に夕食だけ変更するので、以下のように記述します。
const healthyGohan = gohan
healthyGohan.dinner = "サラダ"
console.log(healthyGohan) // { morning:"パン", lunch:"カレー", dinner:"サラダ" }
これで、無事 healthyGohan の夕食はサラダになりました。しかしこの時、問題が発生しました。
console.log(gohan) // { morning:"パン", lunch:"カレー", dinner:"サラダ" }
なんと毎日の献立が helthyGohan と同じように「サラダ」に変更されてしまいました。
このような変更をオブジェクトの状態が変わる ミュータブルな変更といいます。
JavaScriptでは、オブジェクトが格納されている変数を他の変数にコピーすると、そのオブジェクトへの参照がコピーされます。したがって、healthyGohanが変更されたら、その参照元のgohanまでもが変更されます。
等価演算子(==)で確認すると、healthyGohan と gohan は同じオブジェクトだということが分かります。
healthyGohan == gohan // true
イミュータブル(mutable)な変更
Object.assign()
参照元を変更したくない場合は、オブジェクトの状態が変わらない イミュータブルな変更をする必要があります。
イミュータブルな変更を行う方法の一つに、Object.assign() があります。
Object.assign(target, ...sources)
target: コピー先オブジェクト
sources: コピー元オブジェクト
空のオブジェクト をコピー先オブジェクトにすることで、イミュータブルなオブジェクトのコピーができます。
今回の例だと以下のようにしてオブジェクトをコピーします。
const healthyGohan2 = Object.assign({}, gohan) // {}は空のオブジェクト
console.log(healthyGohan2) // { morning:"パン", lunch:"カレー", dinner:"ラーメン" }
これで、healthyGohan2 はgohanをコピーしました。しかし、等価演算子(==)で確認すると、見た目は同じでも違うオブジェクトだということがわかります。
healthyGohan2 == gohan // false
イミュータブルな変更なので、夕食をサラダに変更しても参照元のgohanは変更されません。
healthyGohan2.dinner = "サラダ"
console.log(healthyGohan2) // { morning:"パン", lunch:"カレー", dinner:"サラダ" }
console.log(gohan) // { morning:"パン", lunch:"カレー", dinner:"ラーメン" } // dinnerはラーメンのまま
Object.assign()はオブジェクト同士の結合も可能です。寝る前にプロテインを摂るとします。
const midnight = {midnight:"プロテイン"}
Object.assign(healthyGohan2, midnight)
console.log(healthyGohan2) // { morning:"パン", lunch:"カレー", dinner:"サラダ", midnight:"プロテイン" }
イミュータブルな変更なので、参照元のgohanは変更されません。
console.log(gohan) // { morning:"パン", lunch:"カレー", dinner:"ラーメン" }
スプレッド演算子
スプレッド演算子を使うことで、Object.assign()と同じように、オブジェクトをイミュータブルに扱うことができます。
const healthyGohan3 = {...gohan}
console.log(healthyGohan3) // { morning:"パン", lunch:"カレー", dinner:"ラーメン" }
healthyGohan3 == gohan // false
以上、ミュータブルな変更とイミュータブルな変更に関して、説明させていただきました。
何か間違っていることや意見等ありましたら、コメントいただけると助かります!
参考