数字营销 · Web开发 · 基础设施

jQuery中noConflict的实现原理

本文结合 jQuery 的源码,简单分析 noConflict() 的实现原理。通过保存 $ 和 jQuery 原有的全局变量,并在需要时恢复变量控制权,避免多个 JavaScript 类库同时使用全局变量时产生冲突。

jQuery 中,noConflict 是用来处理全局变量冲突、释放变量控制权的一个重要方法。

我们知道,jQuery 对外提供了两个常用的全局变量:$jQuery。虽然一般情况下只使用 jQuery 时不会出现冲突,但如果网页中同时引入了多个 JavaScript 类库,或者自定义了 $jQuery 等全局变量,就有可能产生变量冲突。

jQuery 提供的 noConflict 函数很好地解决了这个问题。无论是 $ 还是 jQuery 发生冲突,都可以通过相应的方式进行处理。接下来就来看一下 jQuery 是如何实现变量冲突处理的。

先来看一下 jQuery 源码中 noConflict 的实现:

(function(window, undefined) {

// Map over jQuery in case of overwrite
var _jQuery = window.jQuery,

// Map over the $ in case of overwrite
_$ = window.$;

jQuery.extend({
noConflict: function(deep) {

if (window.$ === jQuery) {
window.$ = _$;
}

if (deep && window.jQuery === jQuery) {
window.jQuery = _jQuery;
}

return jQuery;
}
});

}(window));

这里的 jQuery.extend 是用来给 jQuery 扩展静态属性和方法的,可以简单理解为直接在 jQuery 上增加了一个 noConflict 方法。

在匿名函数内部,首先定义了 _jQuery_$ 两个内部变量,分别保存当前的 window.jQuerywindow.$

var _jQuery = window.jQuery,
_$ = window.$;

这样做的作用,是在 jQuery 接管这两个全局变量之前,先把它们原来的状态保存起来,以便后面发生冲突时进行恢复。

noConflict 可以处理 $jQuery 这两个变量的冲突。默认情况下只释放 $

jQuery.noConflict();

如果传入 true

jQuery.noConflict(true);

则会同时释放 $jQuery 两个全局变量。

来看下面这段代码:

if (window.$ === jQuery) {
window.$ = _$;
}

它的意思是:只有当前的 $ 仍然指向 jQuery 时,才把 $ 恢复成 jQuery 加载之前保存的值。

对于 jQuery 变量也是一样:

if (deep && window.jQuery === jQuery) {
window.jQuery = _jQuery;
}

当开启深度冲突处理,并且当前的 window.jQuery 仍然指向 jQuery 时,才把它恢复成之前保存的 _jQuery

这里的判断非常重要。它的作用是避免已经被其他代码重新定义的变量再次被覆盖。

例如:

// 引入 jQuery 库

var $ = "String";

var jq = jQuery.noConflict();

var jQuery = "This is a line";

var j = jq.noConflict(true);

console.log($);
console.log(jQuery);

如果没有:

window.$ === jQuery

这个判断,那么 noConflict() 在恢复 $ 时,可能会直接把后来重新定义的 $ 覆盖掉。

同样,如果没有:

window.jQuery === jQuery

这个判断,那么开启深度冲突处理后,后来重新定义的 jQuery 变量也可能再次被之前保存的值覆盖。

所以,noConflict 的实现原理其实并不复杂:先保存 jQuery 接管 $jQuery 之前的值,在需要时恢复这些值,同时判断当前变量是否仍然由 jQuery 控制,避免误覆盖后来重新定义的变量。

整个运行流程如下图

jQuery中的noConflict原理

最后,noConflict() 返回的是 jQuery 本身,因此可以把它保存到另一个变量中继续使用:

varjq=jQuery.noConflict();jq("div").hide();

这样,即使 $ 已经释放,仍然可以通过 jq 来使用 jQuery。

评论0

欢迎分享你的看法,也欢迎补充不同的实践经验。