WEBサービス創造記

WEBサービスを作ったり保守したりしてる人のメモブログです。

JavaScriptでの即時実行関数と関数上書きのユースケース

      2015/09/17

この記事の内容

普段あまり使わない、JavaScriptでの即時実行関数と関数の上書きを使う機会がありました。
コードを書いてみた感触は悪くなかったため、備忘録として残します。

実装例として用いる機能とその要件

よくあるフォームの実装として、セレクトボックスである値が選択されている場合にのみ、あるフィールドを表示させるというのがある。
例えば、下記画面はお問い合わせフォームだが、お問い合わせの種類に「商品について」が選択された場合にURL入力フィールドを表示させるという要件になっている。

js-instant-func-example-form

このようなケースではJavaScript(jQuery)でセレクトボックスが選択されたイベントを拾って実装することになるが、標題の自己実行関数と関数の上書きの組み合わせでいい感じで実装できる。

即時実行関数と関数上書きを使わないコード

真っ先に書いたコードは下記。

$(function () {
    "use strict;"

    $("select#type").on("change", function () {
        if (this.value != 1) {
            $("form .url-group").css("display", "none");
        } else {
            $("form .url-group").css("display", "block");
        }
    });

});

これでOKな気がするが、「商品について」以外の種類が選択されている状態でページを再読込すると、URL入力フィールドが表示されたままになってしまう。

即時実行関数と関数上書きを使ったコード

そこで、下記のようにコードを修正する。

$(function () {
    "use strict;"

    var display_url_group_type = 1;

    // 1. 即時実行関数を定義
    change_url_group_display_property = function() {
        // ※ここは初回実行時のみ実行される
        if ($("select#type").val() == display_url_group_type) {
            $("form .url-group").css("display", "block");
        } else {
            $("form .url-group").css("display", "none");
        }

        // 2. 関数を上書きする
        return function() {
            if (this.value == display_url_group_type) {
                $("form .url-group").css("display", "block");
            } else {
                $("form .url-group").css("display", "none");
            }
        }
    }();

    // 3. 上書き後の関数をコールバックとして登録する
    $("select#type").on("change", change_url_group_display_property);

});

これで上記アクション実行時でも、URL入力フィールドは非表示となる。

ページ読み込み時とセレクトボックスの選択時に同様の処理を行うが、ページ読み込み時は1回しか処理を行わない。
そこで、1.で即時実行関数を定義。この関数内でページ読み込み時の判定を実行している。

同じ性質の処理をセレクトボックス選択時のコールバック関数でも行うが、別途関数を作るのは無駄なので、2.の部分で関数自体を上書きしちゃう。
上書き後の関数を3.に登録。

使い捨ての処理を効率よく書けることと、関数の上書きでページ読み込み時の関数・コールバックとして登録する関数を分けて実装する必要がない。

最終的なソースは以下のとおり。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>JavaScriptの即時実行関数と関数の上書きのユースケース</title>
</head>
<body>
<form action="">
    <label for="type">お問い合わせの種類</label>
    <select id="type" name="type">
        <option value="1">商品について</option>
        <option value="2">サービスについて</option>
        <option value="0">その他</option>
    </select>
    <br>
    <div class="url-group">
        <label for="url">商品のURL</label>
        <input name="url" type="text" id="url">
    </div>
    <label for="content">内容</label>
    <textarea name="content" cols="50" rows="10" id="content"></textarea>
    <br>
    <input type="submit" value="お問い合わせを送信">
</form>

<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script type="text/javascript">
$(function () {
    "use strict;"

    var display_url_group_type = 1;

    change_url_group_display_property = function() {
        if ($("select#type").val() == display_url_group_type) {
            $("form .url-group").css("display", "block");
        } else {
            $("form .url-group").css("display", "none");
        }

        return function() {
            if (this.value == display_url_group_type) {
                $("form .url-group").css("display", "block");
            } else {
                $("form .url-group").css("display", "none");
            }
        }
    }();

    $("select#type").on("change", change_url_group_display_property);

});
</script>
</body>
</html>

あとがき

直したほうがいい点などありましたらご指摘お願いします。

※ここでは便宜上、HTMLファイルにJavaScriptやCSSをベタ書きしましたが、実際は外部ファイルに書いてます

追記

後からみたらぜんぜんDRYじゃなくて酷いコードだったので以下のように書き直しました。

$(function () {
    "use strict;"

    var display_url_group_type = 1;

    var change_url_group_display_property = function() {
        if ($(this).value == display_url_group_type) {
            $("form .url-group").css("display", "block");
        } else {
            $("form .url-group").css("display", "none");
        }
    };

    change_url_group_display_property.call($("select#type"));

    $("select#type").on("change", change_url_group_display_property);

});

やりたいこと(この場合は即時実行関数)を目の前の実装で無理やり使おうと思ったらダメですね。

参考資料

 - JavaScript , ,