JavaScript

レシピ

オブジェクト

オブジェクトを編集できないようにする

特定のオブジェクトのプロパティを編集できないようにする方法について解説します。

この記事のポイント

  • オブジェクトを編集できないように凍結するにはfreezeメソッドを使う
  • 凍結してもプロパティの値の更新だけ許可するときはsealメソッドを使う
  • 凍結する対象はオブジェクトの直下にあるプロパティのみ

目次

オブジェクトを凍結して編集できないようする

あるオブジェクトに対して、プロパティの値の更新、プロパティ自体の追加や削除を禁止するときはfreezeメソッドを使用します。
このメソッドを実行して凍結したオブジェクトは、凍結以降は一切編集できない状態になります。

以下の例では変数johnに入っているオブジェクトに対してfreezeメソッドを使って凍結を行い、その後にプロパティの更新をしても値が更新されないことを確認します。

コード例

// (1)オブジェクトを作成
var john = {
  id: 15001,
  name: 'John',
  job: 'Fisherman'
}

// (2)プロパティ「age」を追加し、プロパティ「job」を削除
john.age = 30;
delete john.job;

console.log(john);
// {id: 15001, name: "John", age: 30}

console.log(Object.isFrozen(john));
// false


// (3)オブジェクトを凍結
Object.freeze(john);
console.log(Object.isFrozen(john));
// true


// (4)プロパティ「age」を更新し、プロパティ「job」を再度追加
john.age = 31;
john.job = 'Fisherman';

console.log(john);
// {id: 15001, name: "John", age: 30}

まず、通常のプロパティ更新作業として(1)で作成したオブジェクトに対し、(2)でプロパティ「age」の追加、および「job」の削除を行っています。
その後のconsole.logメソッドによる出力内容をみると、正常にプロパティが更新できていることが分かります。

凍結する直前にisFrozenメソッドを実行していますが、このメソッドはオブジェクトが凍結されているかを確認することができます。
この時点ではまだ凍結していないためfalseが返されます。

(3)でfreezeメソッドを使い、変数johnのオブジェクトを凍結します。
凍結後に改めてisFrozenメソッドを実行すると、今度は凍結されているためtrueが返ってきます。

(4)はプロパティの更新を行おうとしますが、すでに凍結しているため実際には何も起こりません。
最後にオブジェクトの内容をconsole.logメソッドで出力してみると、(4)の更新は反映されていないことが確認できます。

以上の処理の流れから、freezeメソッドで凍結するとプロパティを更新できなくなることが確認できました。
一度凍結すると解除することはできません
プロパティの追加や削除はできなくても、途中でプロパティの値は更新したいときがあるかもしれません。
そのときは、次に解説するsealメソッドを使って少し緩めの凍結をします。

プロパティの値だけは更新できるように凍結する

上記のfreezeメソッドは実行するとオブジェクトが完全に凍結するため一切の更新ができなくなってしまいますが、姉妹メソッドのsealメソッドを使うとプロパティ値の更新だけはできる状態で凍結することができます。

以下の例では変数johnに入っているオブジェクトに対してsealメソッドを使って凍結を行い、その後にプロパティの値を更新して確認します。

コード例

// (1)オブジェクトを作成
var john = {
  id: 15001,
  name: 'John',
  job: 'Fisherman'
}


// (2)プロパティの値を追加 & 削除
john.age = 30;
delete john.job;

console.log(john);
// {id: 15001, name: "John", age: 30}

console.log(Object.isSealed(john));
// false


// (3)オブジェクトを凍結
Object.seal(john);
console.log(Object.isSealed(john));
// true


// (4)プロパティの値を更新
john.id = 15005;
john.age = 22;
john.job = 'Teacher';
delete john.id;

console.log(john);
// {id: 15005, name: "John", age: 22}

オブジェクトの作成から(2)のプロパティ追加と削除まではfreezeメソッドのときと同じですが、凍結状態を確認するメソッドをisSealedメソッドに置き換えています。
isSealedメソッドsealメソッドによる凍結状態を確認するためのメソッドで、sealメソッドで凍結されていたらtrue、凍結していないときはfalseを返します。
(2)の段階ではまだ凍結していないのでfalseが返されます。

(3)でオブジェクトを凍結後、(4)でプロパティの値の更新、追加、削除をそれぞれ実行します。
実行後のオブジェクトの内容をconsole.logメソッドで確認すると、値の更新はちゃんと反映されますが、プロパティ「job」の追加と「id」の削除については反映されていないことが分かります。

このように、sealメソッドはプロパティ値の更新する機能だけを残してオブジェクトを凍結することができます。
オブジェクトの編集を一切認めない場合はfreezeメソッド、プロパティの値の更新だけ許可して他は編集できないようにする場合はsealメソッドと使い分けることができます。

入れ子になったオブジェクトは凍結されない

freezeメソッドsealメソッドはともに、凍結する対象がオブジェクトの直下にあるプロパティになります。
もしオブジェクトのプロパティに別のオブジェクトが入った入れ子状態のときは、そのプロパティも凍結するには別でfreezeメソッドを実行する必要があります。

実際にコードを使って、挙動を解説していきます。
以下の例では、変数johnに入っているオブジェクトに対してfreezeメソッドを使って凍結を行い、その後に入れ子になったオブジェクトに対してもfreezeメソッドで凍結します。

コード例

// (1)オブジェクトを作成
var john = {
  id: 15001,
  name: 'John',
  job: 'Fisherman',
  contact: {
    'tel': '03-1111-2222',
    'email': 'john@gray-code.com'
  }
}

// (2)オブジェクトを凍結
Object.freeze(john);
console.log(Object.isFrozen(john));
// true
console.log(Object.isFrozen(john.contact));
// false


// (3)プロパティ「contact」内のオブジェクトを更新
john.contact.tel2 = '080-3333-4444';
delete john.contact.tel;

console.log(john.contact);
// {email: "john@gray-code.com", tel2: "080-3333-4444"}


// (4)プロパティ「contact」内のオブジェクトを凍結
Object.freeze(john.contact);
console.log(Object.isFrozen(john.contact));
// true


// (5)プロパティ「contact」内のオブジェクトを再度更新
john.contact.tel3 = '8131-5555-6666';
delete john.contact.tel2;

console.log(john.contact);
// {email: "john@gray-code.com", tel2: "080-3333-4444"}

オブジェクトのを作成した直後に(2)でfreezeメソッドを実行します。
このとき、直下にある4つのプロパティは凍結されますが、プロパティ「contact」の中にあるオブジェクトについては凍結されません。

そのため、(3)で「contact」に入っているオブジェクトのプロパティを更新すると、ここでは反映されていることが確認できます。

そこで、(4)で「contact」のオブジェクトに対して改めてfreezeメソッドを実行して凍結します。
すると、今度は(5)の箇所で「contact」に入っているプロパティを更新しようとしても反映されなくなりました。

このように、freezeメソッドが凍結できるのはオブジェクトの直下(第1階層)のみになり、入れ子になっているときはその階層に対してもfreezeメソッドを実行する必要があります。

これはsealメソッドも全く同じ挙動になります。
以下のコード例ではfreezeメソッドsealメソッドに置き換えて、凍結状態を確認するisFrozenメソッドisSealedメソッドに置き換えています。

コード例

// (1)オブジェクトを作成
var john = {
  id: 15001,
  name: 'John',
  job: 'Fisherman',
  contact: {
    'tel': '03-1111-2222',
    'email': 'john@gray-code.com'
  }
}

// (2)オブジェクトを凍結
Object.seal(john);
console.log(Object.isSealed(john));
// true
console.log(Object.isSealed(john.contact));
// false


// (3)プロパティ「contact」内のオブジェクトを更新
john.contact.tel2 = '080-3333-4444';
delete john.contact.tel;

console.log(john.contact);
// {email: "john@gray-code.com", tel2: "080-3333-4444"}


// (4)プロパティ「contact」内のオブジェクトを凍結
Object.seal(john.contact);
console.log(Object.isSealed(john.contact));
// true


// (5)プロパティ「contact」内のオブジェクトを再度更新
john.contact.tel2 = '8131-7777-8888';
john.contact.tel3 = '8131-5555-6666';
delete john.contact.tel2;

console.log(john.contact);
// {email: "john@gray-code.com", tel2: "8131-7777-8888"}

全体の流れはfreezeメソッドのときと同様ですが、最後の(5)で「john.contact.tel2」の値を更新している箇所は異なります。
sealメソッドなので凍結後も値の更新だけはちゃんと反映されます。

こちらの記事は役に立ちましたか?

ありがとうございます。
もしよろしければ、あわせてフィードバックや要望などをご入力ください。

コメントありがとうございます!
運営の参考にさせていただきます。