jQuery / jQuery.noConflict() / 다른 라이브러리, 다른 버전의 jQuery와 충돌 방지하기
jQuery.noConflict()는 jQuery가 사용하기 전의 전역 $를 복원하고 현재 jQuery 함수를 반환합니다. 반환값을 jq 같은 별칭에 저장하면 다른 라이브러리의 $와 함께 사용할 수 있습니다. true를 전달하면 전역 jQuery 이름도 이전 값으로 돌리지만, API·플러그인 호환성까지 해결하는 기능은 아닙니다.
기본 호출과 true 인자의 차이
jQuery.noConflict()는 jQuery 초기화 때 보관한 이전 전역 참조를 복원합니다. 기본 호출은 전역 $를 이전 값으로 복원하고 jQuery 이름은 유지합니다. noConflict(true)는 $와 jQuery 이름 둘 다 이전 값으로 돌릴 때 사용합니다. 이전에 해당 값이 없었다면 다른 라이브러리를 새로 만들어 주는 것이 아닙니다.
반환값은 새로 복제한 라이브러리가 아니라 호출한 jQuery 함수 자체입니다. jq는 별칭일 뿐이라 jq("selector")·jq.ajax()처럼 같은 기능을 사용할 수 있습니다. 전역 $를 다시 jQuery로 대입하면 되돌려 준 이름을 또 빼앗으므로 지역 범위에서 별칭을 사용하는 편이 명확합니다.
다른 라이브러리의 $를 유지하는 전체 예제
전체 코드를 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
- Use local jQuery를 세 번 누르면 clicks=3입니다. 버튼은 지역 $로 등록한 jQuery 이벤트를 사용합니다.
- global dollar는 계속 other library이고 original dollar restored=true입니다. 단순히 같은 반환값뿐 아니라 원래 함수 객체가 복원됐다는 뜻입니다.
- Reset counter로 0으로 되돌립니다. 페이지나 라이브러리를 다시 불러오는 동작은 아닙니다.
문서 준비 콜백인 jq(function ($) { ... })의 인자 $는 호출한 jQuery를 받습니다. 함수 안의 $는 이 인자이며 전역 window.$와 다릅니다. 다른 함수로 코드를 옮길 때도 그 지역 범위를 유지해야 합니다. 문서 준비 콜백을 화살표로 바꿔도 인자를 받는다는 목적은 같지만, 이벤트에서 this가 필요한 코드는 별도로 검토합니다.
두 jQuery 버전을 분리하는 전체 예제
새 파일 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
- global jQuery와 global dollar는 먼저 읽은 3.7.1로 돌아갑니다. modern alias는 나중에 읽은 4.0.0을 유지합니다.
- Legacy handler를 한 번, Modern handler를 두 번 누르면 legacy clicks=1; modern clicks=2입니다. 저장한 두 참조로 이벤트를 등록했습니다.
- lessonOnly는 legacy.fn에만 등록했으므로 modern plugin=undefined입니다. 같은 DOM 요소의 .data("owner")도 legacy/modern으로 따로 읽힙니다.
- Reset counters는 두 카운터만 0으로 되돌립니다. 전역 이름과 로딩 순서는 바꾸지 않습니다.
이름 분리로 해결되지 않는 문제
두 인스턴스는 같은 문서를 조작합니다. .data() 저장소와 플러그인 등록은 별도여도 한쪽이 DOM을 지우거나 속성을 바꾸면 다른 쪽에도 같은 문서 변경이 보입니다. 이벤트 해제·데이터 정리도 어느 인스턴스로 등록했는지 맞춰 관리해야 합니다. 이름을 나눴다고 독립된 화면 두 개가 되는 것은 아닙니다.
전역 jQuery를 참조하는 플러그인은 어느 버전이 전역에 있는 시점에 로딩했는지에 따라 다른 인스턴스에 등록될 수 있습니다. noConflict(true) 뒤 전역을 지웠거나 이전 버전으로 돌렸다면, 새 버전 전용 플러그인이 자동으로 modern에 붙는다고 생각하지 않습니다. 각 플러그인의 지원 버전과 로딩 방식을 확인합니다.
jQuery의 충돌 방지 안내에 따라 라이브러리 로딩 직후 이름을 정리하고, 기능 코드는 보관한 참조를 사용하도록 일관되게 작성합니다. ‘$ is not a function’만 보고 noConflict를 무조건 추가하기보다 콘솔에서 실제 전역 값, jq.fn.jquery와 플러그인 메서드 존재 여부를 확인합니다. 파일 로딩 실패나 버전 제거 API는 별도의 원인입니다.
워드프레스처럼 이미 jQuery를 관리하는 환경에는 이 실습의 CDN 파일 두 개를 그대로 추가하지 않습니다. 등록된 의존성과 기존 스크립트의 지역 별칭 방식을 먼저 확인합니다. 되돌릴 때도 보관한 참조와 의존 플러그인의 소유권을 확인하며, 전역 이름을 임의로 덮어써 다른 기능을 깨뜨리지 않도록 합니다.




