コードを書いていくと「この処理は良く使うからメソッドとして切り出そう」というケースが多々出てくると思います。
例えば...
// ゼロ埋めするやつ
function zeroPad(num, len){
let zero = "";
for(let i = 0; i < len; i++){
zero += "0";
}
return `${zero}${num}`.slice(-len);
}
的なやつです。
そして振り返ると、グローバル空間には大量発生した細かいメソッドが...!
カプセル化
グローバル変数が増えるのはあまり喜ばしい事ではありません。
頭数を減らす為に、オブジェクトでカプセル化してみましょう。
const MyUtil = {
zeroPad(){
// ぜろうめ
},
foo(){
// ほげほげ
},
bar(){
// ふがふが
}
};
グローバル変数はMyUtil
だけになりました😉
しかし、これにはひとつ弱点があります。
// 既存プロパティorメソッドの上書き
MyUtil.zeroPad = "上書き";
// 新規プロパティ・メソッドの追加
MyUtil.afterAdd = "後付け";
好き勝手し放題😭
もっとも、自分で書いたコードならそんな真似はしないと思いますが...
なんかこう「これはユーティリティだよ!弄らないで!」っていうアピールが欲しいですね。
編集禁止
そこでObject.freeze()
の出番です。
これに通されたオブジェクトは、文字通り 凍結 されます。
つまりプロパティの編集が出来なくなり "読取専用" となります。
const MyUtil = Object.freeze({
zeroPad(){
// ぜろうめ
},
foo(){
// ほげほげ
},
bar(){
// ふがふが
}
});
これでMyUtil
は鉄壁となりました。
なお凍結されたプロパティの変更を試みた場合、通常モードとStrictモードで挙動が少し異なります。
// 通常モード
MyUtil.afterAdd = "後付け"; // 無視される(エラーは出ない)
"use strict";
MyUtil.zeroPad = "上書き"; // TypeError
このように編集禁止とする事で「これはユーティリティ」と分かりやすくなり、動作的にも精神衛生的にも安心の実装となるわけです😊
凍結範囲
触れたものを凍結させる最強Object.freeze()
卍ですが、芯まで凍らす事は出来ないようです。
と言うのもObject.freeze()
の効果範囲は直下プロパティ止まりなのです。
その下に更にオブジェクトが存在する場合、配下プロパティは凍結されません。
const MyUtil = Object.freeze({
inner: {
zeroPad(){
// ぜろうめ
}
}
});
この場合MyUtil.inner
の変更は不可能ですが、MyUtil.inner.zeroPad
は変更出来てしまいます。
// 編集不可
MyUtil.inner = "うわがき";
// 編集可能
MyUtil.inner.zeroPad = "うわがき";
さしずめ「シャローフリーズ」といったところでしょうか。
なお、オブジェクト全体を凍結させる「ディープフリーズ」ライブラリがあるようです。
オブジェクトを再帰探索し、最深部から順にObject.freeze()
を適用させている様子です。
使用経験は無いので紹介まで。