jQuery静态方法 type/noConflict 使用和源码分析
本教程我们来讲解一下 jQuery 静态方法 type 及 noConflict 的使用及源码分析,type() 是检测数据类型的工具方法, noConflict() 让渡变量 $ 的 jQuery 控制权,jQuery.type方法是检测数据类型的工具方法,在分析其用法之前先总结下js给我们提供了那些监测数据类型的方法.
一、typeof 操作符
下面是测试代码:
- var data=[],a='123',b=0,c=true,d={1:23},e=[123],f=function(){},g=null,h=undefined,i=Math,j=/$.+^/,k= new Date();
- data.push(a,b,c,d,e,f,g,h,i,j,k);
- for(var key=0;key<data.length;key++){
- console.log(data[key]+'的数据类型是'+typeof data[key]);
- }
在上面的代码中我尽量列举了js不同的数据类型和对象,执行结果如下:
- //123的数据类型是string
- // 0的数据类型是number
- // true的数据类型是boolean
- //[object Object]的数据类型是object
- //123的数据类型是object
- // function (){}的数据类型是function
- //undefined的数据类型是undefined
- // [object Math]的数据类型是object
- // /$.+^/的数据类型是object
- // Wed Jul 22 2015 15:47:25 GMT+0800 (中国标准时间)的数据类型是object
我们可以看到typeof能检测到js的6大基本类型中的5个,即String,Boolean,Number,Undefined,Object 其中null被归为了Object把Function单独拿了出来,基本上还是能完成任务的,但那是对于复合类型而言就无法进一步区分了,比如到底是数组还是对象呢?这个时候就可以利用另外一个操作符instanceOf了
二、instanceOf操作符
同样的写一段测试代码.
- var data=[],a='123',b=0,c=true,d={1:23},e=[123],f=function(){},g=null,h=undefined,i=Math,j=/$.+^/,k= new Date();
- data.push(a,b,c,d,e,f,g,h,i,j,k);
- console.log(a instanceof String);
- console.log(b instanceof Number);
- console.log(c instanceof Boolean);
- console.log(d instanceof Object);
- console.log(e instanceof Array);
- console.log(f instanceof Function);
- console.log(j instanceof RegExp);
- console.log(k instanceof Date);
在浏览器中的运行结果如下:
- // false
- // false
- // true
- // true
- // true
- // true
- // true
可以看到只有复合类型的结果为真,而且必须保证类型是一一对应的,显然这个方法只能做个一检验方法存在,并不能在我们不知道具体数据类型的时候去做判断,可以作为typeof的一个辅助测试手段
三、constructor属性
同样的先写下测试代码
- var data=[],a='123',b=0,c=true,d={1:23},e=[123],f=function(){},g=null,h=undefined,i=Math,j=/$.+^/,k= new Date();
- data.push(a,b,c,d,e,f,g,h,i,j,k);
- for(var key=0;key<data.length;key++){
- try{
- console.log(data[key]+'的检测结果是' +data[key].constructor);
- }catch(e){
- }
- }
运行结果如下:
- //123的检测结果是function String() { [native code] }
- //0的检测结果是function Number() { [native code] }
- //true的检测结果是function Boolean() { [native code] }
- //[object Object]的检测结果是function Object() { [native code] }
- //123的检测结果是function Array() { [native code] }
- //function (){}的检测结果是function Function() { [native code] }
- //[object Math]的检测结果是function Object() { [native code] }
- ///$.+^/的检测结果是function RegExp() { [native code] }
- //Wed Jul 22 2015 16:23:41 GMT+0800 (中国标准时间)的检测结果是function Date() { [native code] }
其中null调用是会报错所以加了try语句,相对而言此方法能够很方便的获取其构造函数,这样就能判断了,遗憾的是该属性并非是只读属性是可以被修改的,一旦被修改或者涉及到对象继承等问题时会导致不准而且在遇到某些值得时候会报错导致程序无法运行比如null,还有没有其他方法呢?
四、Object.prototype.toString方法
该方法通过调用待测试数据的toString方法来获得其构造函数的字符串表示,测试代码如下:
- var data=[],a='123',b=0,c=true,d={1:23},e=[123],f=function(){},g=null,h=undefined,i=Math,j=/$.+^/,k= new Date();
- data.push(a,b,c,d,e,f,g,h,i,j,k);
- for(var key=0;key<data.length;key++){
- console.log(data[key]+'的检测结果是' +Object.prototype.toString.call(data[key]));
- }
运行结果如下:
- //123的检测结果是[object String]
- //0的检测结果是[object Number]
- //true的检测结果是[object Boolean]
- //[object Object]的检测结果是[object Object]
- //123的检测结果是[object Array]
- //function (){}的检测结果是[object Function]
- //null的检测结果是[object Null]
- //undefined的检测结果是[object Undefined]
- //[object Math]的检测结果是[object Math]
- ///$.+^/的检测结果是[object RegExp]
- //Wed Jul 22 2015 16:33:05 GMT+0800 (中国标准时间)的检/测结果是[object Date]
看到结果是不是感觉很爽!不仅可以检测到所有数据类型,而且把Object子类型也现实了出来,也不用担心报错,之所以能实现是因为所有的对象都是基于Object而来的,其实jQery也是采取的这个方法,只不过是做了进一步处理让我们看着更爽而已!
看看使用jQuery.type的结果
- var data=[],a='123',b=0,c=true,d={1:23},e=[123],f=function(){},g=null,h=undefined,i=Math,j=/$.+^/,k= new Date();
- data.push(a,b,c,d,e,f,g,h,i,j,k);
- for(var key=0;key<data.length;key++){
- console.log(data[key]+'的检测结果是' +$.type(data[key]));
- }
运行结果:
- //123的检测结果是string
- //0的检测结果是number
- //的检测结果是boolean
- //[object Object]的检测结果是object
- //123的检测结果是array
- //function (){}的检测结果是function
- //null的检测结果是null
- //undefined的检测结果是undefined
- //[object Math]的检测结果是object
- ///$.+^/的检测结果是regexp
- //Wed Jul 22 2015 16:44:25 GMT+0800 (中国标准时间)的检测结果是date
ok,结果无可挑剔了,下面附上源码:
- type: function( obj ) {
- return obj == null ?
- String( obj ) :
- class2type[ toString.call(obj) ] || "object";
- },
如果是undefined或者是null他们的数据累类型就是自己,直接返回字符串形式,如果是其他数据就执行toString方法,该方法在之前有介绍
toString = Object.prototype.toString,
返回的结果就像之前测试过的结果类似 [object Date]这样的 如果不能取到就返回object,结果作class2type的键,下面来看下class2type的定义:
- // Populate the class2type map
- jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
- class2type[ "[object " + name + "]" ] = name.toLowerCase();
- });
好了type方法分析完毕。
jQuery.noConflict的使用和源码分析
所谓静态方法是jQuery本身得公共方法,并不需要通过实例化来调用,一般也称为工具方法,下面先来列绝下jQuery.noConflict方法的用法:
noConflict() 方法让渡变量 $ 的 jQuery 控制权。
该方法释放 jQuery 对 $ 变量的控制。
该方法也可用于为 jQuery 变量规定新的自定义名称。
var jq=$.noConflict();
下面来做个测试:
- <script src='jquery-1.7.1.js'></script>
- <script>
- alert( $ ); //function(){...}
- </script>
调用noConflict方法之后的结果:
- <script src='jquery-1.7.1.js'></script>
- <script>
- $.noConflict();
- alert( $ ); //undefinded
- </script>
这个时候$就不再是jQuery的别名了,下面加上参数
- <script src='jquery-1.7.1.js'></script>
- <script>
- $.noConflict(true);
- alert( jQuery ); //undefined
- </script>
这样jQuery也被释放出来了许多 JavaScript 库使用 $ 作为函数或变量名,jQuery 也一样。在 jQuery 中,$ 仅仅是 jQuery 的别名,因此即使不使用 $ 也能保证所有功能性。假如我们需要使用 jQuery 之外的另一 JavaScript 库,我们可以通过调用 $.noConflict() 向该库返回控制权:
- <script type="text/javascript" src="other_lib.js"></script>
- <script type="text/javascript" src="jquery.js"></script>
- <script type="text/javascript">
- $.noConflict();
- // 使用另一个库的 $ 的代码
- </script>
可以与 .ready() 方法结合起来使用,不需要为 jQuery 对象起别名,这项技术非常有效:
- <script type="text/javascript" src="other_lib.js"></script>
- <script type="text/javascript" src="jquery.js"></script>
- <script type="text/javascript">
- $.noConflict();
- jQuery(document).ready(function($) {
- // 使用 jQuery $ 的代码
- });
- // 使用其他库的 $ 的代码
- </script>
此外,通过向该方法传递参数 true,我们可以将 $ 和 jQuery 的控制权都交还给原来的库。用之前请考虑清楚!
这是相对于简单的 noConflict 方法更极端的版本,因为这将完全重新定义 jQuery。这通常用于一种极端的情况,比如你想要将 jQuery 嵌入一个高度冲突的环境。注意:调用此方法后极有可能导致插件失效。
- //将 $ 引用的对象映射回原始的对象:
- jQuery.noConflict();
- jQuery("div p").hide(); // 使用 jQuery
- $("content").style.display = "none"; // 使用其他库的 $()
恢复使用别名 $,然后创建并执行一个函数,在这个函数的作用域中仍然将 $ 作为 jQuery 的别名来使用。在这个函数中,原来的 $ 对象是无效的。这个函数对于大多数不依赖于其他库的插件都十分有效:
- jQuery.noConflict();
- (function($) {
- $(function() {
- // 使用 $ 作为 jQuery 别名的代码
- });
- })(jQuery);
- ... // 其他用 $ 作为别名的库的代码
可以将 jQuery.noConflict() 与简写的 ready 结合,使代码更紧凑:
- jQuery.noConflict()(function(){
- // 使用 jQuery 的代码
- });
- ... // 其他库使用 $ 做别名的代码
创建一个新的别名用以在接下来的库中使用 jQuery 对象:
- var j = jQuery.noConflict();
- j("div p").hide(); // 基于 jQuery 的代码
- $("content").style.display = "none"; // 基于其他库的 $() 代码
完全将 jQuery 移到一个新的命名空间:
- var dom = {};
- dom.query = jQuery.noConflict(true);
结果:
- dom.query("div p").hide(); // 新 jQuery 的代码
- $("content").style.display = "none"; // 另一个库 $() 的代码
- jQuery("div > p").hide(); // 另一个版本 jQuery 的代码
下面开始分析jquey源码:
- // Map over jQuery in case of overwrite
- _jQuery = window.jQuery,
- // Map over the $ in case of overwrite
- _$ = window.$,
这段是写在jQuery构造函数里面的,主要用途是保存可能存在的jQuery和$的变量,很有可能使其他库,这样可以避免冲突
- noConflict: function( deep ) {
- if ( window.$ === jQuery ) {
- window.$ = _$;
- }
- if ( deep && window.jQuery === jQuery ) {
- window.jQuery = _jQuery;
- }
- return jQuery;
- },
deep参数是一个布尔值如果为true则释放jQuery为undefined在前面的例子中已经演示过
window.$ === jQuery
这个条件是保证只有当jQuery还拥有$的控制权的时候才去释放,本来就没有释放也没有意义,把刚才的_$再次变为全局变量,而这个$可能是其他库这样就实现了释放的过程
deep && window.jQuery === jQuery
deep为true并且jQuery变量还属于jQuery,跟$一样,如果已经被释放了就没有必要再释放了
return jQuery;
执行后的结果是jQuery,这样就可以把jQuery起一个别用来使用了