由于jQuery的源码比较复杂,所以我选择从jQuery1.0.0版本开始学习,逐步深入。
而且本系列文章包含大量的个人观点,纯属本人学习的记录
jQuery1.0.0只有1800行左右的代码,相对来讲看起来还是比较简单的
首先,想说一下我对jQuery的理解
jQuery其实就是一个很大的构造函数
它为我们提供了很多实例化方法
当然,由于在js中函数本身就是对象
因此jQuery也提供了很多的静态方法
个人认为,这些静态方法更为底层
今天把jQuery的架构梳理了一下
其实我们可以将其中的方法抽出来,这样看起来就像是一个大的构造函数
function jQuery(){} jQuery.prototype={ jquery: "", size: function(){}, get: function(){}, each: function(){}, index: function(){}, attr: function(){}, css: function(){}, text: function(){}, wrap: function(){}, append: function(){}, prepend:function(){}, before: function(){}, after: function(){}, end: function(){}, find: function(){}, clone: function(){}, filter: function(){}, not: function(){}, add: function(){}, is: function(){}, domManip:function(){}, pushStack:function(){}, extend: function(){}, //*扩展其他实例化对象方法的核心方法 appendTo: function(){}, //*通过macros的to 扩展的方法 prependTo: function(){}, //*通过macros的to 扩展的方法 insertBefore: function(){}, //*通过macros的to 扩展的方法 insertAfter: function(){}, //*通过macros的to 扩展的方法 width: function(){}, //*通过macros的css扩展的方法 height: function(){}, //*通过macros的css扩展的方法 top: function(){}, //*通过macros的css扩展的方法 left: function(){}, //*通过macros的css扩展的方法 position: function(){}, //*通过macros的css扩展的方法 float: function(){}, //*通过macros的css扩展的方法 overflow: function(){}, //*通过macros的css扩展的方法 color: function(){}, //*通过macros的css扩展的方法 background: function(){}, //*通过macros的css扩展的方法 eq: function(){}, //*通过macros的filter扩展的方法 lt: function(){}, //*通过macros的filter扩展的方法 gt: function(){}, //*通过macros的filter扩展的方法 contains: function(){}, //*通过macros的filter扩展的方法 val: function(){}, //*通过macros的attr扩展的方法 html: function(){}, //*通过macros的attr扩展的方法 id: function(){}, //*通过macros的attr扩展的方法 title: function(){}, //*通过macros的attr扩展的方法 name: function(){}, //*通过macros的attr扩展的方法 href: function(){}, //*通过macros的attr扩展的方法 src: function(){}, //*通过macros的attr扩展的方法 rel: function(){}, //*通过macros的attr扩展的方法 parent: function(){}, //*通过macros的axis扩展的方法 ancestors: function(){}, //*通过macros的axis扩展的方法 parents: function(){}, //*通过macros的axis扩展的方法 next: function(){}, //*通过macros的axis扩展的方法 prev: function(){}, //*通过macros的axis扩展的方法 siblings: function(){}, //*通过macros的axis扩展的方法 children: function(){}, //*通过macros的axis扩展的方法 removeAttr: function(){}, //*通过macros的each扩展的方法 show: function(){}, //*通过macros的each扩展的方法 hide: function(){}, //*通过macros的each扩展的方法 toggle: function(){}, //*通过macros的each扩展的方法 addClass: function(){}, //*通过macros的each扩展的方法 removeClass: function(){}, //*通过macros的each扩展的方法 toggleClass: function(){}, //*通过macros的each扩展的方法 remove: function(){}, //*通过macros的each扩展的方法 empty: function(){}, //*通过macros的each扩展的方法 bind: function(){}, //*通过macros的each扩展的方法 unbind: function(){}, //*通过macros的each扩展的方法 trigger: function(){}, //*通过macros的each扩展的方法 _toggle: function(){}, toggle: function(){}, hover: function(){}, ready: function(){}, blur: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 focus: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 load: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 resize: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 scroll: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 unload: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 click: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 dbclick: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 mousedown: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 mouseup: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 mousemove: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 mouseover: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 mouseout: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 change: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 reset: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 select: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 submit: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 keydown: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 keypress: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 keyup: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 error: function(){}, //*同时绑定了un解绑定方法和one只触发一次的方法 //*由于上面已经定义过一个show方法,所以这里通过_show将其存储起来,否则下面的show方法会将其覆盖 _show: function(){}, //*动画方法 show: function(){}, _hide: function(){}, hide: function(){}, slideDown: function(){}, slideUp: function(){}, slideToggle: function(){}, fadeIn: function(){}, fadeOut: function(){}, fadeTo: function(){}, animate: function(){}, queue: function(){}, loadIfModified: function(){}, //*ajax方法 load: function(){}, ajaxStart: function(){}, ajaxStop: function(){}, ajaxComplete: function(){}, ajaxError: function(){}, ajaxSuccess: function(){} }; jQuery.extend= function(){}; jQuery.init= function(){}; jQuery.each= function(){}; jQuery.className={}; jQuery.swap= function(){}; jQuery.css= function(){}; jQuery.curCSS= function(){}; jQuery.clean= function(){}; jQuery.expr= function(){}; jQuery.token= function(){}; jQuery.find= function(){}; jQuery.getAll= function(){}; jQuery.attr= function(){}; jQuery.parse= []; jQuery.filter= function(){}; jQuery.trim= function(){}; jQuery.parents= function(){}; jQuery.sibling= function(){}; jQuery.merge= function(){}; jQuery.grep= function(){}; jQuery.map= function(){}; jQuery.event= {}; jQuery.browser= function(){}; //*browser方法要基于变量b b=navigator.userAgent.toLowerCase(); jQuery.boxModel=function(){}; //*boxModel方法要基于browser方法 jQuery.macros= {}; //*由此派生出若干实例化对象的方法 jQuery.isReady= false; //*load模块 jQuery.readyList=[]; jQuery.ready= function(){}; jQuery.setAuto= function(){}; //*动画模块 jQuery.speed= function(){}; jQuery.queue= function(){}; jQuery.dequeue= function(){}; jQuery.fx= function(){}; jQuery.get= function(){}; //*ajax模块 jQuery.getIfModified=function(){}; jQuery.getScript=function(){}; jQuery.post= function(){}; jQuery.timeout= 0; jQuery.ajaxTimeout=function(){}; jQuery.lastModifed=function(){}; jQuery.ajax= function(){}; jQuery.active= 0; jQuery.httpSuccess=function(){}; jQuery.httpModified=function(){}; jQuery.httpData=function(){}; jQuery.param= function(){};
当然这里面省略了很多的细节
在梳理的过程中,发现了很多的问题,如下:
1、看到jQuery.macros的时候感觉很晕,后来才发现macros其实是把相关的方法或者属性名放到了一起,在合适的时机去初始化
例如macros.to下面的appendTo prependTo insertBefore insertAfter这四个方法就是在DOM模块被初始化的
2、v1.0.0对于避免污染全局空间的做法是用new function(){}形成封闭空间,由于之前本人一直用(function(){xxx})();来处理此类情况
所以看到new function(){}有些无所适从,后来通过查阅相关资料才发现这种方法其实相当于new Aaa;
new是js中的一个单目运算符,new后面的方法名的括号是可以省略的,所以完整的写法应该是new function(){}() 其中function(){}就相当于一个函数名
new function(){}通常用来初始化一些东西,但又没有污染全局对象
3、梳理到动画模块的时候,看到有_show和show两个方法瞬间石化了,不知道是干啥的,
经过高手指点才发现,在之前的实例化方法中,已经有一个show方法了,所以在定义第二个show方法的时候先用了一个_show方法将第一个show方法存了起来,
之所以存期来,是因为第二个show方法中需要调用第一个show方法
附带一句个人之拙见:jQuery的作者为什么不再起一个别的名字额外定义一个方法呢?非得弄成两个同名的方法,还用一个变量缓冲,搞不明白John Resig是怎么想的
hide和_hide也是同样的道理
4、本以为作者在处理两个名字一样的方法时就会通过_xxx来存储,但是例外出现在load,我很惊奇的发现实例化对象中有两个load方法
这样一来后面的load不就覆盖了前一个load了吗?后来定睛一看才发现后面的这个load方法可以大大方方的覆盖前一个load方法,没有任何关系
因为后面一个load方法实现了前一个load方法的所有功能,而且还扩展了和ajax相关的新的功能
但是感觉还是不对劲,既然后面的能实现,为什么前面还写一个load方法,感觉前面的load方法定义的既重复又没用
不过后来经过仔细分析,发现我又错了,因为第一个load方法是通过如下方法加到jQuery的实例化对象上的:
var e = ("blur,focus,load,resize,scroll,unload,click,dblclick," + "mousedown,mouseup,mousemove,mouseover,mouseout,change,reset,select," + "submit,keydown,keypress,keyup,error").split(","); for ( var i = 0; i < e.length; i++ ) new function(){ var o = e[i]; jQuery.fn[o] = function(f){ return f ? this.bind(o, f) : this.trigger(o); }; jQuery.fn["un"+o] = function(f){ return this.unbind(o, f); }; jQuery.fn["one"+o] = function(f){ ..... }; };
也就是说,人家除了绑定load方法之外还绑定了unload和oneload方法,要是按照我当初想的那样来变量e中去掉load的话
后面ajax模块还得将unload和oneload方法也加上去,那样就更麻烦了
所以采用了现在前面定义再覆盖的形式