jQueryの”おまじない”を紐解いてみる。(jQuery.noConflict())

jQueryの”おまじない”を紐解いてみる。(jQuery.noConflict())

はじめに

no conflict(競合しない)という位なんだから、「名称」なのか「処理」なのかわからんが

何かしらを競合しないように整備してくれているんだろう。。。

としか思っていなかったので、この”おまじない”を今更紐解いてみる。

そもそも何と競合しているのか

ざっと調べると、解説しているほぼ全てのページで、prototype.jsが例として挙げられていた。

prototype.jsはMITライセンスで使用可能なライブラリで、

Prototype JavaScript Framework は、Sam Stephenson が開発したJavaScriptフレームワークであり、Ajaxフレームワークやその他のユーティリティを提供する。

との事(参考:Wikipedia)。

jQueryも幅広く利用可能だが、prototype.jsも広範囲をカバーしているライブラリのようだ。

そしてこちらのサイトで詳しく記載されているが、グローバルの名前空間に

幾つかオブジェクトを定義しており、その中に「$」が使用されているとの事。

ちなみに「document.getElementById」

つまり、prototype.jsとjQueryを同時に使用した場合、

prototype.jsがグローバルに定義した「$」と、jQueryのエイリアスである「$」が

競合してしまう(というように理解した)。

競合させてみる

「競合」とはどのような状態を指すのか、試してみたいと思う。

ブログタイトルが設定されたテキストフィールドしか存在しない質素すぎるページ。

これをサンプルとする。

index.html

<input type="text" id="conflict-textfield" value="trial and error">
※要素IDは conflict-textfield
conflict.js
// jQueryでテキストフィールドの値を取得
console.log($('#conflict-textfield').val());
// prototype.jsでテキストフィールドの値を取得
console.log($('conflict-textfield').value);
jQueryとprototype.jsで値を取得するだけのJS。
jQueryでは$()にセレクタを指定し、.val()で値を取得している。
prototype.jsでは$()に要素IDを指定し、.valueで値を取得している。

jQuery ⇒ prototype.js の順で読み込み

jQuery⇒prototype.jsの順にライブラリを読み込みます。

index.html

        <!-- jQuery -->
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <!-- prototype.js -->
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.3/prototype.min.js"></script>
        <!-- 2つのライブラリを使用するJavaScript -->
        <script type="text/javascript" src="./js/conflict.js"></script>

実行結果

jQueryの値取得 val()でエラーになりました。

後に読み込んだprototype.jsの「$」でjQueryの「$」が上書きされたようです。
それを確認する為、jQueryで値取得している行をコメントにしてもう一度実行します。
(エラーが発生すると処理が中断される為)
conflict.js
// jQueryでテキストフィールドの値を取得
// console.log('jQuery で値を取得 ⇒ ' + $('#conflict-textfield').val());
// prototype.jsでテキストフィールドの値を取得
console.log('prototype.js で値を取得 ⇒ ' + $('conflict-textfield').value);

実行結果

prototype.jsでは正常に値を取得できている。

両方のライブラリがエイリアス「$」を使おうとして競合していると言えます。

prototype.js ⇒ jQuery の順で読み込み

prototype.js ⇒ jQuery の順にライブラリを読み込みます。

index.html

        <!-- prototype.js -->
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.3/prototype.min.js"></script>
        <!-- jQuery -->
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <!-- 2つのライブラリを使用するJavaScript -->
        <script type="text/javascript" src="./js/conflict.js"></script>

実行結果

今度はprototype.jsでエラーになりました。

後から読み込んだjQueryに「$」が上書きされている事によるエラーと思われる。

解決策

そこで出てくるのが jQuery.noConflict()

これはjQueryがエイリアスとして定義している「$」を”解放”し、競合を防ぐというもの。

jQuery.noConflict()実行後は、「jQueryオブジェクト」のエイリアスである「$」を解放するので、「jQuery」と明示する必要があります。

それを踏まえて conflict.js を修正します。

conflict.js

jQuery.noConflict();
// jQueryでテキストフィールドの値を取得
console.log('jQuery で値を取得 ⇒ ' + jQuery('#conflict-textfield').val());
// prototype.jsでテキストフィールドの値を取得
console.log('prototype.js で値を取得 ⇒ ' + $('conflict-textfield').value);

1行目でjQuery.noConflict()を実行し、

3行目で「$」ではなく「jQuery」で実行するように修正しています。

実行結果

jQuery、prototype.js 両方で正常に値を取得できました。

または即時関数を使用して

jQuery.noConflict();
// jQueryでテキストフィールドの値を取得
// console.log('jQuery で値を取得 ⇒ ' + jQuery('#conflict-textfield').val());
(function($) {
console.log('jQuery で値を取得 ⇒ '+$('#conflict-textfield').val());
})(jQuery);
// prototype.jsでテキストフィールドの値を取得
console.log('prototype.js で値を取得 ⇒ ' + $('conflict-textfield').value);

このようにすることもできます。

個人的にはこの方がスマートのように思います。

参考

jQuery日本語リファレンス

JavaScriptカテゴリの最新記事