
JavaScriptのオブジェクトを保護する
JavaScriptではオブジェクトがよく利用されます。
JavaScriptではAPIでJSONなどでデータを取得することが多いが、その中のデータの大半はオブジェクトです。
そのため、JavaScriptでオブジェクトの内容を保護したいことがよくあります。
constやreadonlyでは保護できない
よく誤解されるのですが、JavaScriptではconst宣言やTypeScriptのreadonlyではオブジェクトを保護できず、書き換えが可能になっています。
// JavaScript
const obj = { a: 123 }
obj.a = 444
console.log(obj.a) // 444
// TypeScript
const obj: { readonly a: number } = { a: 123 }
obj.a = 555
console.log(obj.a) // 555
※ TypeScriptの場合はtsconfig.jsonのcompilerOptionsで "noEmitOnError": true が指定されている場合はコンパイルされない。
オブジェクトの代入による書き換えやdeleteによる削除はObject.freeze()、deleteの削除だけならObject.seal()を使用すれば無効にできます。
Object.freeze()の使い方
Object.freeze()メソッドはオブジェクトを代入で変更したり、deleteで削除されないようにできます。
const obj = Object.freeze({ a: 123 })
obj.a = 444
delete obj.a
console.log(obj.a) // 123
Object.isFrozen()を使うとObject.freeze()が使われているか確認できます。
Object.isFreeze()ではないので注意が必要です。
const foo = { a: 1 }
const bar = Object.freeze({ a: 1 })
console.log(Object.isFrozen(foo)) // false
console.log(Object.isFrozen(bar)) // true
Object.seal()の使い方
Object.seal()メソッドはオブジェクトをdeleteで削除されないようにできます。
Object.freeze()と違って代入はできます。
const foo = Object.seal({ a: 1 })
foo.a = 2
console.log(foo) // {a: 2}
delete foo.a
console.log(foo) // {a: 2}
Object.isSealed()を使うとObject.seal()が使われているか確認できます。
Object.isSeal()ではないので注意が必要です。
const foo = { a: 1 }
const bar = Object.seal({ a: 1 })
console.log(Object.isSealed(foo)) // false
console.log(Object.isSealed(bar)) // true
一度使用したら解除不可
Object.freeze()およびObject.seal()を使用したオブジェクトは保護されている状態を解除できません。
Object.seal()の変数をObject.freeze()に変更することはできます。
let foo = Object.seal({ a: 1 })
foo = Object.freeze(foo)
foo.a = 2
console.log(foo) // {a: 1}
delete foo.a
console.log(foo) // {a: 1}
しかし、Object.freeze()をObject.seal()にはできません。
let foo = Object.freeze({ a: 1 })
foo = Object.seal(foo)
foo.a = 2
console.log(foo) // {a: 1}
delete foo.a
console.log(foo) // {a: 1}
すでにObject.freeze()が使われているのにObject.seal()を使ってしまうミスなどはありえるので、覚えておくと良いでしょう。