Tips

【※重要】JavaScriptのObject.freezeのよくある勘違い

  • このエントリーをはてなブックマークに追加

「オブジェクトと配列を定数で固定してるのに値の更新が行われる」
「Object.freezeまでやっているのに値を固定できていない」

本日はそんな方に向けてObject.freezeの正しい使い方を解説します。

また動画もあるので必要に応じて使ってください。

JavaScriptでオブジェクトと配列の更新を禁止する

まず定数constでオブジェクトと配列を定義した場合に、プロパティについては値の更新ができてしまうのが背景にあります。

「オブジェクトと配列をconstで定義しているのに中身が変わってしまう」という方は、まずそこから知っておく必要があります。

詳細は別記事で既に取り上げているので参考にしてください。

そんな時にJavaScriptではObject.freezeという関数が用意されていて、引数に固定したいオブジェクトもしくは配列を入れることでプロパティの更新を禁止することができます。

// 通常のオブジェクトの書き方
const student = {
  id: "0001",
  name: "山田",
  age: 18,

};
student.id = "0002";
console.log(student.id); // "0002"と更新されて出力されてしまう

// Object.freezeを使った書き方
const student = Object.freeze({
  id: "0001",
  name: "山田",
  age: 18,
});
student.id = "0002";
console.log(student.id); // "0001"のままで出力される

上記のようなシンプルな作りだと困ることはないのですが、以下のような入れ子になったオブジェクトと配列は気を付けないといけません。

const student = Object.freeze({
  id: "0001",
  name: "山田",
  age: 18,
  // こちらを追加
  address: {
    preference: "Tokyo",
    block: "Akabane",
  },
});
student.address.block = "Setgaya";
console.log(student.address.block); // "Setagaya"と更新されて出力されてしまう

なんとObject.freezeを設定しているのにプロパティの更新が実行されてしまいました。

こちらエラーではなく通常の動作でして、公式ドキュメントにも明記されているんです。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze

簡単に言うとObject.freezeは「入れ子の深いところまでは対応できない」とのことです。

そのため入れ子の深い部分まで固定したい場合には、中身でもObject.freezeを使う必要があります。

const student = Object.freeze({
  id: "0001",
  name: "山田",
  age: 18,
 // ここでもObject.freezeを使う
  address: Object.freeze({
    preference: "Tokyo",
    block: "Akabane",
  }),
});
student.address.block = "Setgaya";
console.log(student.address.block); // "Akabane"のままで出力される

ちなみに値の更新だけでなく、新規追加でも同じことが言えます。

多いケースとして配列のpushがよく使われますね。

const student = Object.freeze({
  id: "0001",
  name: "山田",
  age: 18,
  address: Object.freeze({
    preference: "Tokyo",
    block: "Akabane",
  }),
 // こちらを追加
  circles: ["football", "tennis"],
});
student.circles.push("baseball");
console.log(student.circles); // ["football", "tennis", "baseball"]と出力されてしまう

上記の場合もプロパティにまでObject.freezeを使う必要があります。

const student = Object.freeze({
  id: "0001",
  name: "山田",
  age: 18,
  address: Object.freeze({
    preference: "Tokyo",
    block: "Akabane",
  }),
  circles: Object.freeze(["football", "tennis"]),
});
student.circles.push("baseball");
console.log(student.circles); // ["football", "tennis"]のまま出力される

APIなど連想配列でデータが構成されることは当たり前になってきましたので、オブジェクトと配列の扱いには注意しましょう。

  • このエントリーをはてなブックマークに追加