三分钟带你玩转jQuery.noConflict()


Posted in Javascript onFebruary 15, 2016

jQuery是目前使用最广泛的前端框架之一,有大量的第三方库和插件基于它开发。为了避免全局命名空间污染,jQuery提供了jQuery.noConflict()方法解决变量冲突。这个方法,毫无疑问,非常有效。遗憾的是,jQuery的官方文档对该方法的描述不够清晰,许多开发者并不清楚当他们调用jQuery.noConflict()时,究竟发生了什么,从而导致在使用时出现了许多问题。尽管如此,jQuery.noConflict()背后实现原理依然值得Web开发者学习掌握,成为解决类似全局命名空间污染问题的利器。

jQuery.noConflict()的作用?

  jQuery.noConflict()的存在只有一个目的:它允许你在同一个页面加载多个jQuery实例,尤其是不同版本的jQuery。你可能会觉得奇怪,为什么要在一个页面加载/使用多个不同版本的jQuery对象呢?一般而言,有两种情况。第一种情况,你的业务代码采用了最新版的jQuery库,而你选用的第三方插件依赖的更早版本的jQuery库;第二种情况,你正维护着一个系统,它已有的业务代码由于各种原因,引用了较老版本的jQuery库,你新开发的模块采用的是其他版本的jQuery库。不论哪种情况,你都不得不面对,jQuery对象/方法冲突的问题。幸运的是,jQuery.noConflict()帮你解决了这个烦恼。

jQuery被加载时发生了什么?

当jQuery被页面引用/加载时,它被封装在一个自执行函数(匿名函数)里,它提供的所有一切变量、函数、对象都在匿名函数内部的可执行环境内,外部环境无法调用,以防止全局命名空间污染。

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

jQuery在匿名函数内部定义了两个全局对象:jQuery和$,把自己暴露给外部环境。开发者习惯使用的各种公共方法都是通过这两个对象进行访问的,如jQuery.ajax(),jQuery.css()等。在最初,它们指向匿名函数内部的同一个对象jQuery(私有变量),通过它访问匿名函数内部的私有变量和函数。这使得匿名函数在自执行后其内部的私有变量和函数仍然进驻在内存里,不会被javascript的垃圾回收机制清除。

window.jQuery = window.$ = jQuery;

当jQuery被页面加载后,当前页面有可能已经存在了jQuery和$这两个全局变量(比如,加载了其它的第三方库,其内部也定义了它俩),这就会导致已经存在的对象被覆盖(全局命名空间污染)。为了解决这个问题,jQuery在内部先将已经存在的全局变量缓存起来,保存在私有变量_jQuery和_$中,供后续调用。所以,如果页面在加载jQuery库时,还不存在jQuery和$对象,那么_jQuery和_$都是undefined;否则,它们都会保存对已有jQuery和$的引用(也许来自之前引用的第三方库或是不同版本的jQuery库)。之后,jQuery会像上文说描述的那样,覆盖这两个全局变量并将自己暴露给外部环境。至此,页面上的全局变量jQuery和$已经指向刚刚引入的jQuery库。

// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$,
// Otherwise expose jQuery to the global object as usual
window.jQuery = window.$ = jQuery;

jQuery.noConflict()的神奇效果?

假设你维护的系统已经引用了1.7.0版本的jQuery库,而你在新添加的功能里引用了1.10.2版本的jQuery库。那么,还有办法重新使用jQuery 1.7.0 或是同时使用两个版本的jQuery库吗?答案是肯定,那就是jQuery.noConflict()。实际上,利用jQuery.noConflict(),你可以立刻把全局变量jQuery和$重新指向之前引用的对象。很神奇吧?这就是为什么jQuery在对外暴露自己前内部缓存了之前引用的对象。

  jQuery.noConflict()接受一个可选的布尔值参数,通常默认值是false。这个参数会带来什么影响呢?其实,很简单。如果调用jQuery.noConflict()或是jQuery.noConflict(false),只有全局变量$会被重置恢复成之前的引用值;如果调用jQuery.noConflict()或是jQuery.noConflict(true),那么全局变量jQuery和$都会被重置恢复成之前的引用值。这一点非常重要,建议牢记。当你调用jQuery.noConflict(false/true)之后,它会返回当前jQuery的实例,利用这个特性我们可以实现jQuery的重命名。

// "Renaming" jQuery
var jayquery = jQuery.noConflict( true );
// Now we can call things like jayquery.ajax(), jayquery.css(), and so on

我们再来看一个代码片段,测试一下是否真正理解了神奇的noConflict()

<!-- jQuery and $ are undefined -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<!-- jQuery and $ now point to jQuery 1.10.2 -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js">
<!-- jQuery and $ now point to jQuery 1.7.0 -->
<script>jQuery.noConflict();</script>
<!-- jQuery still points to jQuery 1.7.0; $ now points to jQuery 1.10.2 -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js">
<!-- jQuery and $ now point to jQuery 1.6.4 -->
<script>var jquery164 = jQuery.noConflict( true );</script>
<!-- jQuery now points to jQuery 1.7.0; $ now points to jQuery 1.10.2; jquery164 points to jQuery 1.6.4 -->

避免第三方库的冲突

以上的代码片段展示了如何解决多版本jQuery的冲突。接下来,我们尝试解决jQuery库和第三方库的冲突,下面出现的代码片段在jQuery的官方文档中都有,有兴趣的程序猿可以仔细阅读官方文档体会其中的区别。

直接使用No-Conflict模式

使用No-Conflict模式,其实就是对jQuery进行重命名,再调用。

<!-- 采用no-conflict模式,jquery.js在prototype.js之后被引入. -->
<script src="prototype.js"></script>
<script src="jquery.js"></script>
<script>
var $j = jQuery.noConflict();
// $j 引用了jQuery对象本身.
$j(document).ready(function() {
$j( "div" ).hide();
});
// $ 被重新指向prototype.js里定义的对象
// document.getElementById(). mainDiv below is a DOM element, not a jQuery object.
window.onload = function() {
var mainDiv = $( "main" );
}
</script>

使用自执行函数封装

使用这种方式,你可以在匿名函数内部继续使用标准的$对象,这也是众多jQuery插件采用的方法。需要注意的是,使用这种方法,函数内部无法再使用prototype.js定义的$对象了。

<!-- jquery.js在prototype.js之后被引入. -->
<script src="prototype.js"></script>
<script src="jquery.js"></script>
<script>
jQuery.noConflict();
(function( $ ) {
// Your jQuery code here, using the $
})( jQuery );
</script>

使用标准jQuery(document).ready()函数

如果jQuery库在其它库之前引入,那么jQuery内部定义的jQuery和$会被第三方库覆盖,这时候再使用noConflict()已经没有什么意义了。解决的方法很简单,直接使用jQuery的标准调用方式。

<!-- jquery.js在prototype.js之前被引入. -->
<script src="jquery.js"></script>
<script src="prototype.js"></script>
<script>
// Use full jQuery function name to reference jQuery.
jQuery( document ).ready(function() {
jQuery( "div" ).hide();
});
// 或者
jQuery(function($){
// Your jQuery code here, using the $
});
// Use the $ variable as defined in prototype.js
window.onload = function() {
var mainDiv = $( "main" );
};
</script>

下面给大家介绍jQuery noConflict() 方法

noConflict() 方法会释放会 $ 标识符的控制,这样其他脚本就可以使用它了。

实例

当然,您仍然可以通过全名替代简写的方式来使用 jQuery:

$.noConflict();
jQuery(document).ready(function(){
jQuery("button").click(function(){
jQuery("p").text("jQuery 仍在运行!");
});
});

实例

您也可以创建自己的简写。noConflict() 可返回对 jQuery 的引用,您可以把它存入变量,以供稍后使用。请看这个例子:

var jq = $.noConflict();
jq(document).ready(function(){
jq("button").click(function(){
jq("p").text("jQuery 仍在运行!");
});
});

实例

如果你的 jQuery 代码块使用 $ 简写,并且您不愿意改变这个快捷方式,那么您可以把 $ 符号作为变量传递给 ready 方法。这样就可以在函数内使用 $ 符号了 - 而在函数外,依旧不得不使用 "jQuery":

$.noConflict();
jQuery(document).ready(function($){
$("button").click(function(){
$("p").text("jQuery 仍在运行!");
});
});
Javascript 相关文章推荐
用JS实现的一个include函数
Jul 21 Javascript
js 获取class的元素的方法 以及创建方法getElementsByClassName
Mar 11 Javascript
Javascript执行效率全面总结
Nov 04 Javascript
JS数组的赋值介绍
Mar 10 Javascript
jquery使用$(element).is()来判断获取的tagName
Aug 24 Javascript
浅谈关于JavaScript API设计的一些建议和准则
Jun 24 Javascript
Javascript 高性能之递归,迭代,查表法详解及实例
Jan 08 Javascript
微信小程序 数据封装,参数传值等经验分享
Jan 09 Javascript
详解webpack 配合babel 将es6转成es5 超简单实例
May 02 Javascript
ES6解构赋值实例详解
Oct 31 Javascript
vue.js2.0点击获取自己的属性和jquery方法
Feb 23 jQuery
JS正则表达式常见用法实例详解
Jun 19 Javascript
轻松搞定jQuery.noConflict()
Feb 15 #Javascript
JavaScript的Backbone.js框架的一些使用建议整理
Feb 14 #Javascript
简单了解Backbone.js的Model模型以及View视图的源码
Feb 14 #Javascript
Backbone.js框架中简单的View视图编写学习笔记
Feb 14 #Javascript
10个JavaScript中易犯小错误
Feb 14 #Javascript
讲解JavaScript的Backbone.js框架的MVC结构设计理念
Feb 14 #Javascript
深入解析JavaScript框架Backbone.js中的事件机制
Feb 14 #Javascript
You might like
php2html php生成静态页函数
2008/12/08 PHP
PHP对字符串的递增运算分析
2010/08/08 PHP
分享下php5类中三种数据类型的区别
2015/01/26 PHP
WordPress中&quot;无法将上传的文件移动至&quot;错误的解决方法
2015/07/01 PHP
开启PHP的伪静态模式
2015/12/31 PHP
php中strtotime函数性能分析
2016/11/20 PHP
JS加ASP二级域名转向的代码
2007/05/17 Javascript
javaScript checkbox 全选/反选及批量删除
2010/04/28 Javascript
javascript高级学习笔记整理
2011/08/14 Javascript
jquery.tmpl JQuery模板插件
2011/10/10 Javascript
利用cookie记住背景颜色示例代码
2013/11/04 Javascript
JavaScript对IE操作的经典代码(推荐)
2014/03/10 Javascript
玩转JavaScript OOP - 类的实现详解
2016/06/08 Javascript
Bootstrap组件系列之福利篇几款好用的组件(推荐二)
2016/07/12 Javascript
DOM 事件的深入浅出(一)
2016/12/05 Javascript
jQuery实现拖动剪裁图片作为头像
2016/12/28 Javascript
详解如何用webpack打包一个网站应用项目
2017/07/12 Javascript
vue-cli —— 如何局部修改Element样式
2020/10/22 Javascript
[01:32]TI奖金增速竟因它再创新高!DOTA2勇士令状不朽珍藏Ⅰ饰品欣赏
2018/05/18 DOTA
Python中字典的基础知识归纳小结
2015/08/19 Python
Python 创建新文件时避免覆盖已有的同名文件的解决方法
2018/11/16 Python
详解PyCharm安装MicroPython插件的教程
2019/06/24 Python
python 使用opencv 把视频分割成图片示例
2019/12/12 Python
基于torch.where和布尔索引的速度比较
2020/01/02 Python
基于Modernizr 让网站进行优雅降级的分析
2013/04/21 HTML / CSS
Johnston & Murphy官网: 约翰斯顿·墨菲牛津总统鞋
2018/01/09 全球购物
以实惠的价格轻松租车,免费取消:Easyrentcars
2019/07/16 全球购物
波兰在线体育用品商店:Hop-Sport.pl
2019/07/23 全球购物
JNI的定义
2012/11/25 面试题
后勤岗位职责
2013/11/26 职场文书
数控专业个人求职信范例
2013/11/29 职场文书
《威尼斯的小艇》教学反思
2014/02/17 职场文书
一年级学生评语
2014/04/23 职场文书
慰问敬老院活动总结
2014/04/26 职场文书
单位租车协议书
2015/01/29 职场文书
python小程序之飘落的银杏
2021/04/17 Python