📋
[JavaScript] オブジェクト操作をイミュータブルにする
前提
JavaScriptではconstで配列を使用してもあくまで参照元が変わらないことを保証しているだけで中身は変更できる。
MDNでは以下のように書かれている。
const 宣言は、値への読み取り専用の参照を作ります。これは、定数に保持されている値は不変ではなく、その変数の識別子が再代入できないということです。たとえば、定数の中身がオブジェクトの場合、オブジェクトの内容(プロパティなど)は変更可能です。
なのでオブジェクト(配列含む)は基本的にコピーしてから操作する
なお、プリミティブ型はもともとイミュータブルなので書き換えることはできない
forEach, map, filter, reduce ... は扱わない(These are 教養!)
ここでは可変な操作を不変で置き換える方法一覧を置いておく
Array
push()
const newArray = [...ary, elm1, elm2]
unshift()
const newArray = [elm1, elm2, ...ary]
pop()
const elm = ary[length-1]
const newArray = ary.slice(0, ary.length-1)
shift()
const elm = ary[0]
const newArray = ary.slice(1)
splice()
const newArray = [...ary.slice(0, 1), ...[elm1, elm2], ...ary.slice(2)]
sort()
const newArray = [...ary].sort()
reverse()
const newArray = [...ary].reverse()
Object
Object.preventExtensions()
: 追加 ×
Object.seal()
: 追加、削除 ×
Object.freeze()
: 追加、削除、変更 ×
プロパティ追加 obj.newKey = newValue
const newObj = {...obj, newKey1: newValue1, newKey2: newValue2}
既存のプロパティ変更 obj.existKey = newValue
const newObj = {...obj, existKey1: newValue1, existKey2: newValue2 }
プロパティの削除 delete obj.existKey
const { existKey1, existKey2, ...newObj} = obj
ネストした構造の場合
個別にスプレッド構文{...obj}を使った後に個別に変更
const newObj = {
...obj,
existKey1: [...obj.existKey1],
existKey2: {...obj.existKey2}
}
// ↓元のobjは変わらない
newObj.existKey1.push('newValue')
newObj.existKey2.childkey = 'newValue'
{...JSON.parse(JSON.stringify(ary))}をした後に個別に変更
const newObj = {
...JSON.parse(JSON.stringify(obj)),
}
// ↓元のobjは変わらない
newObj.existKey1.push('newValue')
newObj.existKey2.childkey = 'newValue'
参考URL
Discussion