LoginSignup
6
1

More than 3 years have passed since last update.

ユーティリティはObject.freezeで束ねよう!

Posted at

コードを書いていくと「この処理は良く使うからメソッドとして切り出そう」というケースが多々出てくると思います。

例えば...

// ゼロ埋めするやつ
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()を適用させている様子です。
使用経験は無いので紹介まで。

SpecialThanks!

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1