Corredor

ウェブ、プログラミングの勉強メモ。

jQuery の「$」の名前衝突を避けたりとか読み込みチェックとか

jQuery と prototype.js を併用しているウェブアプリケーションだと、「$」という変数名が衝突するので、$() ではなく jQuery() と書いて避けたりしていた。この辺の知見を

jQuery を安全に使うには、以下をテンプレートにしてしまうと良い。

<script src="/js/jquery-1.4.2.min.js"></script>
<script>window.jQuery || document.write('<script src="/js/jquery-1.12.4.min.js"><\/script>');</script>
<script>
  (function() {
    jQuery.noConflict();
    jQuery(function($) {
      // ココに処理
    });
  })();
</script>

1つずつ説明。

  • 1行目:<script src="/js/jquery-1.4.2.min.js"></script>

まずは普通に jQuery を読み込む。普通なら CDN から jQuery を読み込む書き方をする部分かと。

  • 2行目:<script>window.jQuery || document.write('<script src="/js/jquery-1.12.4.min.js"><\/script>');</script>

グローバル変数 jQuery が存在していれば何もしない。存在していなければ、document.write() でその場に script 要素を書き出し、別の jQuery を読み込む。大抵は自サーバーに保管してある jQuery の JS ファイルを読み込むような処理。

自分が担当しているウェブアプリでは、複数のバージョンの jQuery が混在していて、それがサーバーサイドのテンプレートエンジンによって、「ある画面では 1.4.2 を使う」「この画面では 1.12.4 を使う」というように場合分けされてレンダリングされている。しかしその条件分岐が完璧ではなかったようで、結果的に「先読みされているバージョンを優先して使う」という無茶苦茶なやり方を実現するために、こうした記述になっていた。ちなみに原型は以下で、やっていることは同じ。

<script>
  (function() {
    if(typeof jQuery == "undefined") {
      document.write('<script src="/js/jquery-1.12.4.min.js"><\/script>');
    }
  })();
</script>

なお、document.write() 内に書く </script> 部分は、</ をエスケープして <\/script> と書いてやる必要がある

そして、document.write() を行う箇所 (2行目全体) は、単独の script 要素で囲っておく。3行目以降の script 要素内に混ぜ込んで書いても上手く動かないので、2行目は独立した script 要素で扱う。これはどうも、document.write() で書き出される内容が、script 要素の閉じタグのところで書き出される動きをしているからなようだ。だから3行目以降の script 要素に混ぜ込んでしまうと、最後に document.write() で書いた script 要素が書き出される動きになり、正しく動作しない。

  • 3行目:<script> … そのまま。

  • 4行目:(function() {

無名関数で囲むことで変数のスコープをローカルに保つ。

  • 5行目:jQuery.noConflict();

これを呼ぶと、変数 $ を「jQuery が読み込まれる前の状態」に戻す。つまり、この一連のコードより手前で prototype.js を読み込んでいた場合は、prototype.js のオブジェクトになる。そのため、$jQuery のショートハンドとしては使えなくなり、次の6行目の頭の部分のように、jQuery の ready 関数を呼ぶ時は jQuery(function() {}); という書き方になる。

この関数を実行すると、$関数の動作が先に定義されている動作に戻る。 $ではない文字列にjQueryオブジェクトを割り振る。ここでは、'j'の文字をjQueryオブジェクトとし、$は用いないように。
この方法は汎用的なライブラリを作ることにも利用することにも向かないため、極めて限定的な用途になると考えられる。
var j = jQuery.noConflict();
// jはjQueryとして動作する

この関数は jQuery 自身を戻り値として返すようなので、結果を別の変数に入れれば、$ を元に戻しつつ、別のショートハンドを用意することができる。

元々の $ 関数に戻せるってことは、jQuery は自身を宣言する時に「元々の $ 関数」をどこかで保持しているということなのかな…?なんか恐ろしいことやってるなぁ…。

  • 6行目:jQuery(function($) {

普段の ready 関数 $(function() {}); と同じ構成に見えるが、内側の function の引数に $ を渡している。コレを渡すと、この内側では変数 $ を jQuery として利用できるようになる。


以上。未だ jQuery は多用する。

参考