Object.freeze
Object.freezeすると、そのオブジェクト直下のプロパティを作成変更削除することができなくなります。
class HOGE {
publicProperty;
setPublicProperty(val) {
this.publicProperty = val;
}
}
hoge = new HOGE;
hoge.setPublicProperty(10);
Object.freeze(hoge);
hoge.setPublicProperty(20); // Uncaught TypeError: Cannot assign to read only property
そういう機能として作られたわけなのでまあ当然ですね。
privateプロパティを変更する
ところでprivateプロパティはfreeze後も変更できます。
class HOGE {
#privateProperty;
setPrivateProperty(val) {
this.#privateProperty = val;
}
}
hoge = new HOGE;
hoge.setPrivateProperty(30);
Object.freeze(hoge);
hoge.setPrivateProperty(40); // エラーは出ないし40になる
ええ?
これを見つけたときはけっこうびっくりだったのですが、でもこの事象について言及している記事が全く見当たらなかったので、実はわざわざ言うまでもない周知の事実だったりするのかもしれません。
MDNには一応記載がありました。
プライベート要素は、現在のクラス本体内でのみアクセスすることができ、サブクラスには継承されないため、プロトタイプ継承モデルにはありません。
クラスが異なると、プライベート要素は同じ名前でも全く異なるものであり、相互運用はできません。
クラスごとに管理される、インスタンスに付加された外部メタデータとして考えてください。
このため、 structuredClone() はプライベート要素を複製せず、 Object.freeze() や Object.seal() は、プライベート要素には影響しません。
ただ、知ってから見ればなんとなくわからないでもないですが、この記述だけ読んで『privateプロパティはfreeze後も変更できる』って読み取るのは難しい気がします。
privateプロパティを生やす
かなり無理矢理ですが、freezeしたオブジェクトをexntendsしてprivateプロパティを生やすことができます。
class Base {
constructor() {
Object.freeze(this);
}
}
class Extend extends Base {
#val;
constructor(v) {
super();
this.#val = v;
}
}
const answer = new Extend(42); // 動くし42になる
Object.isFrozen(answer); // true
Object.isSealed(answer); // true
Object.isExtensible(answer); // false
answer.#valは42になってしまいます。
freezeしたのにどうして。
あとどうでもいいけど、isFrozen・isSealedはfreezeされているか・sealされているかを意味するのでtrueなら制限されているのに、isExtensibleは拡張可能かなのでfalseなら制限されていることになるのでわかりにくい。
どうしてこれだけ逆なんですか?
privateプロパティを生やせないようにしよう
ということで、freezeしたオブジェクトはextendsしてもprivateプロパティを生成できないようにしようというproposalが提出されています。
タイトルはDisallow Adding New Private Fields to Non-extensible Objectsで、拡張可能でないオブジェクトにprivateフィールドを生やすことを禁止すると、まあそのまんまの意味ですね。
これが実装されたら、上記のextendsしているコードは動かなくなります。
現在の進捗は、ステージ3で仕様は決定済、あとはブラウザに実装されるのを待つだけという状態です。
ただproposalでは何故かObject.preventExtensionsにしか言及されておらず、freezeやsealについてはどういうわけか一言も書かれていません。
制限の強さは preventExtensions < seal < freeze であり、seal・freezeもNon-extensibleなので、seal・freezeにも影響すると思います。
そのあたりもちゃんとproposalに記載してほしいですね。
誰か詳しい人確認よろ。
V8ExtendingNonExtensibleWithPrivate
Chrome Platform Statusに、この機能がどれくらい使われているかを示すカウンタがありました。
2025年1月あたりに実装されたみたい。
使用率は0.00001%とかであり、まあ無視してもよさそうなレベルに見えますね。
