前言
如果需要理解透jQuery设计的思想,那当然必须要理解什么是jQ对象。
用jQuery的时候经常会听到jQ对象,例如:var dom$ = $(“#id”); 这里的dom$我们成为jQ对象。
那到底这货是啥呢?
这里假定大部分看这篇文章的人都能够懂面向对象的基本想法,面向对象的思想本来就是抽象现实世界的东西,所以要用来讲解某些道理时是很让人接受的,我认为这也就是为什么吹面向对象在大型项目中容易维护的原因之一(因为它符合我们人的思维方式)。
对象剖析
在详细剖析jQ里边实现之前,我想先把一些概念弄清晰一下。
首先用段面向对象的代码稍微解释一下。
(PS:这里的语法不一定符合Java等面向对象语言的语法,只是为了辅助描述而已)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //首先我们定义一个jQuery类,别名是$,下边用$代替 //假设这里定义一个对象 : dom$ = new jQuery('#id'); class jQuery{ //正如我第一篇《jQuery源码剖析(一)——概览&工具方法》写的 //里边有一些静态的工具方法 //可以使用 $.each() / $.map() / $.makeArray() public static each(){} public static map(){} public static makeArray(){} //紧接着是构造函数 jQuery(selector, context, rootjQuery){} //接着是一些成员函数 //我们经常这样使用 // dom$.addClass('cls1'); // dom$.eq(0); // dom$.find('.child'); public addClass(clr){} public eq(idx){} public find(selector){} //这里还有一些静态成员和私有成员 //这些都不是关键的东西,暂时忽略 public static guid; public selector; } |
有了以上的jQuery类之后我们就可以这样使用了
1 2 3 | var dom$ = new jQuery('#id'); dom$.addClass('clr');//成员方法 jQuery.each([], function(){});//静态方法 |
我们把这里的dom$就叫做jQ对象,一切看起来都很顺利。
但是对于一个接口的设计来说,每次需要一个jQ对象,都需要new一下。
能否把这一步new去掉呢?
于是jQuery作者想了个办法:
1 2 3 4 5 6 7 8 9 10 11 | class jQuery{ //内部辅助的初始化函数 class init(){ } //构造函数 jQuery(selector, context, rootjQuery){ return new init(selector, context, rootjQuery); } } |
这样貌似很完美的样子,我们现在直接可以把new去掉了,例如:
1 2 3 | var dom$ = jQuery('#id'); dom$.addClass('clr');//成员方法 jQuery.each([], function(){});//静态方法 |
但是这里出了一个问题,可以看到jQuery构造函数里边返回的是一个内部init类,也就是说dom$是一个init对象。
那怎么能:dom$.addClass(‘clr’);这样调用jQuery类的方法呢?
到了这里貌似一切又不顺利了,于是我决定把prototype的概念拉出来,假设有这样的语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class jQuery{ public static each(){} public static map(){} public static makeArray(){} jQuery(selector, context, rootjQuery){} //内部类 class init(){ } //成员方法 public addClass(clr){} public eq(idx){} public find(selector){} } //等同于 class jQuery{ public static each(){} public static map(){} public static makeArray(){} jQuery(selector, context, rootjQuery){} } jQuery.prototype = { //这个原型对应的构造器是什么 constructor : jQuery //内部类 init : Class //成员方法 addClass : function(clr){} eq : function(idx){} find : function(selector){} } |
我们把一个类的所有内部类/成员方法全部移动到了这个类的原型prototype上去了。
那这一切就完美了。
我只要让:init.prototype = jQuery.prototype;
刚刚说dom$无法调用addClass方法这个问题就解决了!!!
是的,这就是javascript面向对象,实现继承等等的技巧。
可以这么认为:javascript里边的function就是面向对象里边常说的Class。
jQuery构造器源码
接下来就看jQuery的构造器源码吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | // Define a local copy of jQuery //定义一个jQuery类 jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' //这里相当于: //return new jQuery.prototype.init( selector, context, rootjQuery ); //init是一个内部类! return new jQuery.fn.init( selector, context, rootjQuery ); }; //接近着开始定义成员方法,跟内部类 jQuery.prototype = { //指定构造函数 //这样init类生产出来的东西的构造器也是jQuery了! constructor: jQuery, //内部init类 init: function( selector, context, rootjQuery ) { }, //成员变量 length: 0, //成员方法 size: function() {}, toArray: function() {}, get: function() {}, }; //看到没,jQuery类的所有成员方法是在prototype里边的 //jQuery里边还用了另一个引用去记录:fn //名字很好理解,就是function的缩写 jQuery.fn = jQuery.prototype; //为了让init类生成的是一个jQuery对象 //于是乎就要:init.prototype = jQuery.prototype; //也即是这样:jQuery.prototype.init.prototype = jQuery.prototype; jQuery.fn.init.prototype = jQuery.fn; |
在下一篇会把jQuery里边的core.js剩余剖析完。
会剖析一下:jQuery的类数组属性,init内部类怎么实现,jQuery类的成员方法。
转载声明:本博客文章若无特别说明,皆为原创,转载请注明来源:拉风的博客,谢谢!
详细的讲解了jQuery的实例化机制,很棒。
在此补充一下,function除了是类,而且function也是构造函数。
而且是个引用类型,是个对象
你好 看了你的文章我发现一处错误,第14行你保存了当前的原型对象,但是之后又重新赋值,那么jQuery.fn和之后的jQuery.prototype指向的就不是同一个对象了
谢谢指正,已经更正了