关注:国内开源jQuery-UI组件库:Operamasks-UI
jQuery版本:v1.7.1
jQuery1.7系列一: jQuery 对象的实质
一.何为jQuery对象
用过jQuery的朋友都知道,jQuery很大的一个特点就在于其选择器上,我们可以很容易对众多的dom节点进行操作,而且还是链式的操作,这一切都要得益于jQuery对象,那么jQuery对象到底是什么?
我们经常写类似这样的代码: jQuery(“div”).addClass(“myCls”),而这里jQuery(“div”)返回的结果就是jQuery对象,其实它也就是一个javascript对象来的,只是这个对象的创建过程比较复杂而已,而只有理解好了jQuery对象的实质,才能更好的深入学习jQuery。
二.jQuery对象创建的背后
为了把握好jQuery对象的创建,有必要对其创建过程进行一个深入的分析。以下代码是jQuery对象创建的一个架子,我们可以由此来学习。
(function( window, undefined ) {
var jQuery = (function() {
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
},
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function(selector, context, rootjQuery){
//做一些初始化工作,比如查找对应选择器的dom元素
},
length: 0
//其它一些东西
};
jQuery.fn.init.prototype = jQuery.fn;
return jQuery;
})();
window.jQuery = window.$ = jQuery;
})(window);
接下来,我们一步一步来解开jQuery对象的谜底。
1. 最外层的闭包代码是这样的:
(function( window,undefined ) {
})(window);
把window对象传进去了,这倒没什么,有趣的是为什么会有个undefined 的形参? 在javascript语言中,Undefined是其中的一个类型,而其类型值只有 undefined 一个,就像Number也是其中的一个类型,但类型值却有多个,如100,20,88等等。而这个 undefined是用来标识一个未赋值的变量的,就比如声明一个变量 var fun , 这时fun的值就为undefined。但是由于有些古老的浏览器并不直接认识undefined,然而在调用函数传递参数时如果形参个数大于实参,后边的形参却会被赋值真正的undefined,所以像上边这种写法是最保险的,能够保证闭包的形参undefined 一定是Undefined类型的唯一值 undefined.
如果觉得有点晕,看下边这个例子。
var a =undefined;
在某些旧浏览器中,如果它不能直接认识undefined,那么这样写应该会报undefined 这个变量没有定义的错误,而如果这样写
(function(undefined){
var a = undefined;
})();
那么就一定不会报错了,所以jQuery还是考虑得很周到的。
2. 让我们再次精简代码,看看这个jQuery到底是什么
var jQuery = (function() {
var jQuery = function(selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
},
return jQuery;
})();
window.jQuery = window.$ = jQuery;
在使用的时候,我们是这样写的 $(“div”),而这个$其实就是下边这个函数,
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector,context, rootjQuery );
},
所以执行 var $obj = $(“div”)就相当于执行
var $obj= return new jQuery.fn.init( "div", context, rootjQuery );
到这里,我们便了然于胸,原来所谓的jQuery对象就是jQuery.fn.init这个函数的一个实例而已。
上边最原始的骨架图现在还剩下两句比较难懂的语句,它们是
jQuery.fn= jQuery.prototype = {}; //代码1
jQuery.fn.init.prototype= jQuery.fn; //代码2
为了更清晰到底发生了什么事,我们直接看执行这两句代码后结果如何:
由以上图可以看出,这时候,init函数的prototype已经指向了jQuery.fn 所指向的对象,那也就是说,如果我向fn添加属性的话,那么 new init() 得到的实例也就相应可以找到新加的属性了,这也就是jQuery的插件机制。
比如,你想添加一个方法,判断选择器中是否包括了表单,那么该插件大致可以这样写:
$.fn.containsForm = function(){
var i=0,
el;
while(el=this[i++]){
if(el.tagName.toLowerCase() === ‘form’){
return true;
}
}
return false;
}
然后就可以直接使用该插件了,如 $(“myform”).containsForm();
jQuery对象主要就是这样了,顺便还谈到了jQuery对fn的扩展机制,在jQuery的源码中,对jQuery对象添加了很多便利的方法,如addClass,find等,都是通过这种方式实现的。