jQuery / noConflict()で他ライブラリ・別バージョンとの衝突を避ける

jQuery.noConflict()はjQuery以前のグローバル$を復元し、現在のjQuery関数を返します。jqなどに保存すれば他ライブラリの$と共存できます。trueならグローバルjQueryも以前へ戻しますが、APIやプラグイン互換性は解決しません。

基本呼び出しとtrue

jQuery.noConflict()は初期化時に保存した参照を戻します。通常は$だけ、trueはjQueryも対象です。以前に値がなければ古いライブラリを新しく作るわけではありません。

戻り値は複製ではなく同じ関数です。jq("selector")やjq.ajax()で使えます。グローバル$へ再代入すれば名前を再び奪うため地域範囲を使います。

他の$を保つ完全な例

全コードをUTF-8のnoconflict-demo.htmlに保存し開きます。インターネットで公式jQueryファイル4.0.0を読みます。サーバーや導入は不要です。先頭の関数は模擬の所有者で実外部ライブラリではありません。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Return the global dollar alias</title>
  <script>
    // A mock owner, not a real third-party library.
    window.$ = function () { return "other library"; };
    window.previousDollar = window.$;
  </script>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <script>
    const jq = jQuery.noConflict();
    jq(function ($) {
      let clicks = 0;
      function report() {
        $("#result").text(`global dollar=${window.$()}\noriginal dollar restored=${window.$ === window.previousDollar}\nglobal jQuery kept=${window.jQuery === jq}\nlocal alias=${$ === jq}\nclicks=${clicks}`);
      }
      $("#add").on("click", function () { clicks++; report(); });
      $("#reset").on("click", function () { clicks = 0; report(); });
      report();
    });
  </script>
  <style>body { font: 16px/1.6 sans-serif; margin: 20px; } button { font: inherit; margin: 4px; } pre { white-space: pre-wrap; overflow-wrap: anywhere; }</style>
</head>
<body>
  <button type="button" id="add">Use local jQuery</button>
  <button type="button" id="reset">Reset counter</button>
  <pre id="result" aria-live="polite"></pre>
</body>
</html>

初期結果です。全体$は復元され、jQueryとコールバック内$はjQueryです。Windows Edgeで3.7.1・4.0.0を別々に実行しました。

global dollar=other library
original dollar restored=true
global jQuery kept=true
local alias=true
clicks=0
  1. Use local jQueryを三回でclicks=3です。地域jQueryのイベントです。
  2. global dollarはother libraryのままです。original dollar restored=trueは元関数の同一性を確認します。
  3. Reset counterは読込なしで0へ戻します。

DOM準備コールバックjq(function ($) { ... })の引数は呼び出したjQueryです。地域$とwindow.$は異なります。コード移動後も範囲を保ちます。矢印も引数を受けられますが、イベントのthisは別に確認します。

二バージョンの完全な例

次を別のtwo-versions-demo.htmlに保存します。3.7.1をlegacyへ保管し、4.0.0直後のnoConflict(true)をmodernへ保管します。読込順が必要なのでasyncを追加しません。

可能ならサイトのjQueryは一つに統一します。これは既存の混在画面の名前管理を説明する診断例です。lessonOnlyは模擬プラグインで実製品の互換性試験ではありません。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Two jQuery instances with explicit owners</title>
  <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
  <script>
    const legacy = jQuery;
    legacy.fn.lessonOnly = function () { return "legacy plugin"; };
  </script>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <script>
    const modern = jQuery.noConflict(true);
    modern(function ($) {
      let oldClicks = 0, newClicks = 0;
      const element = document.getElementById("shared");
      legacy(element).data("owner", "legacy");
      modern(element).data("owner", "modern");
      function report() {
        $("#result").text([
          "global jQuery=" + window.jQuery.fn.jquery,
          "global dollar=" + window.$.fn.jquery,
          "modern alias=" + modern.fn.jquery,
          "same function=" + (legacy === modern),
          "legacy plugin=" + legacy("#shared").lessonOnly(),
          "modern plugin=" + typeof modern.fn.lessonOnly,
          "shared data=" + legacy(element).data("owner") + "/" + modern(element).data("owner"),
          "legacy clicks=" + oldClicks + "; modern clicks=" + newClicks
        ].join("\n"));
      }
      legacy("#old").on("click", function () { oldClicks++; report(); });
      modern("#new").on("click", function () { newClicks++; report(); });
      modern("#reset").on("click", function () { oldClicks = newClicks = 0; report(); });
      report();
    });
  </script>
  <style>body { font: 16px/1.6 sans-serif; margin: 20px; } button { font: inherit; margin: 4px; } pre { white-space: pre-wrap; overflow-wrap: anywhere; }</style>
</head>
<body>
  <p id="shared">One DOM element, two instance-specific data stores.</p>
  <button type="button" id="old">Legacy handler</button>
  <button type="button" id="new">Modern handler</button>
  <button type="button" id="reset">Reset counters</button>
  <pre id="result" aria-live="polite"></pre>
</body>
</html>

実際の両バージョンをWindows Edgeで同時に読み込んだ初期結果です。

global jQuery=3.7.1
global dollar=3.7.1
modern alias=4.0.0
same function=false
legacy plugin=legacy plugin
modern plugin=undefined
shared data=legacy/modern
legacy clicks=0; modern clicks=0
  1. グローバル二名は3.7.1へ、modernは4.0.0を維持します。
  2. Legacy handler一回、Modern handler二回でlegacy clicks=1; modern clicks=2です。
  3. lessonOnlyはlegacy.fnだけにありmodern plugin=undefinedです。同一DOM要素のownerデータもlegacy/modernです。
  4. Reset countersは数だけ戻し、名前と順番は保ちます。

名前分離で解決しない問題

両方は同じ文書を操作します。データ・プラグインが別でもDOM削除や属性変更は共有します。イベント登録や整理に使うインスタンスを管理します。別々のページになるわけではありません。

全体jQueryを見るプラグインは読込時にある方へ登録します。深い復元後にmodernへ自動登録されません。対応版と読込方式を個別に確認します。

公式の衝突回避資料のように読込直後に名前を整理し、保管参照を統一使用します。「$ is not a function」なら全体値、jq.fn.jquery、メソッドの有無を調べます。取得失敗や削除APIは別原因です。

WordPressのように依存を管理する環境へ実習CDN二つをそのまま足しません。既存依存と地域別名を先に確認します。復元でもプラグイン所有者を確認し全体名を無条件上書きしません。