Thursday, November 24, 2011

javascript で無名関数を使ったコンフリクト回避

javascript を利用するにあたって、グローバルな変数/関数を定義したり、それらをイベント属性からコールする方法は、初心者にも分かりやすく古くから用いられた方法ですが、外部ライブラリを用いたり、複数人開発を行っていく中で、これらのコンフリクトが不安材料になります。

<script>

var messages = ["Foo", "Bar"];

function displayMessages() {
    alert(messages.join("|"));
}
</script>
....
<input type="button" value="Display" onclick="displayMessages();" />

以下のように、無名関数ブロック内でイベントハンドラを使ったコーディングを行う事で、グローバル汚染を回避できます。

<input type="button" value="Display" id="displayButton" />
<script>

(function() {

   // この無名関数ブロック内で定義した変数/関数は、外からはアクセスできません。
 
    var messages = ["Foo", "Bar"];

    function displayMessages() {
        alert(messages.join("|"));
    }

    document.getElementById("displayButton").onclick = function() {
        displayMessages();
    }
 
})();

</script>
...

シンタックスがわかりづらいですが、関数名が (function() {}) になっていると考えると、イメージしやすいと思います。

function displayMessage(str) {
   alert(str);
}
// 以下のコードは同じように動きます。
displayMessage("Foo");
(function(str) { alert(str); })("Foo");

よく知られたところでは Prototype.jsjQuery の変数 $ のコンフリクトがありますが、同様の方法で回避することができます。

(function($) {
    // この無名関数ブロック内では $ は jQuery です。
})(jQuery);

jQuery.noConflict()$ を別名へアサインする方法はありますが、ページ全体のグローバル変数として定義し「jQuery 使うときはこの変数名を使う」といったコーディングは避けた方がよいでしょう。