jQuery 1.7.1 代码研究

  1 /* version : 1.7.1
2 * codeName : jQuery
3 * node author : Alfred lee
4 */
5
6 /* 进入程序首先是个匿名函数。这函数作用就是保护变量。
7 * 关于匿名函数和封包请参见 《javascript语言精粹》
8 * 这里只对源码进行分析。
9 */
10
11 (function(window,undefined){})(window)
12
13 // 定义没默认的全局到这几个变量,定义了主要的jQuery这变量。把初始化的结果传递给了jQuery
14 var document = window.document,
15 navigator = window.navigator,
16 location = window.location;
17 var jQuery = (function(selector,context){
18 //some code in here.
19 return jQuery
20 })();
21 /* 来看看里面主要的函数做了什么吧。
22 * 返回个构造函数。为什么返回个构造函数呢?稍后继续看下jQuery.fn是个什么吧。
23 */
24
25 var jQuery = function(selector,context){
26 return new jQuery.fn.init(selector, context, rootjQuery);
27 },
28 // john 说是为了防止被重写。所以在自己使用的时候用了这个变量。
29 _jQuery = window.jQuery,
30 _$ = window.$,
31 // john 说是为了和默认的jQuery对比
32 rootjQuery,
33
34 // 判断是否是ID 或者是HTML标签。
35 quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
36
37 // 判断是没有空白字符的字符串
38 rnotwhite = /\S/,
39 //干掉前后空白
40 trimLeft = /^\s+/,
41 trimRight = /\s+$/,
42
43 // 匹配独立标签
44 rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
45
46 // 匹配JSON的格式
47 //|-> 数组形式 或者对象格式
48 rvalidchars = /^[\],:{}\s]*$/,
49 //|-> 中文和转义字符"\/\b\f\n\r\t
50 rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
51 //|-> 匹配的boolean和数字以及科学计算法数字。
52 rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
53 //|-> 匹配基本格式是个最起码的对象格式或者数组格式。(是否有标志符号:,[中的一个或者多个)
54 rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
55
56 // 浏览器校验 这不解释了。目前流行的很多检测方法之一
57 rwebkit = /(webkit)[ \/]([\w.]+)/,
58 ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
59 rmsie = /(msie) ([\w.]+)/,
60 rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
61
62 //匹配连线书写(CSS里的属性写法)以及IE -ms-transform 前缀
63 rdashAlpha = /-([a-z]|[0-9])/ig,
64 rmsPrefix = /^-ms-/,
65 // 被jQuery 的一个函数 jQuery.camelCase作为回调使用。转换驼峰书写
66 fcamelCase = function( all, letter ) {
67 return ( letter + "" ).toUpperCase();
68 },
69
70 // 浏览器的信息
71 userAgent = navigator.userAgent,
72 // 为检测浏览器定义的变量
73 browserMatch,
74
75 //DOM 是否完成做记录
76 readyList,
77 //DOM ready 事件的管理函数
78 DOMContentLoaded,
79
80 // 存储一些系统函数方便使用
81 toString = Object.prototype.toString,
82 hasOwn = Object.prototype.hasOwnProperty,
83 push = Array.prototype.push,
84 slice = Array.prototype.slice,
85 trim = String.prototype.trim,
86 indexOf = Array.prototype.indexOf,
87
88 // 最后定义了个对应表。是个[object Object]:Object 的对应表。
89 class2type = {};
90
91 //下面是主要的部分了。jQuery.fn
92 // 为构造函数做铺垫。
93 jQuery.fn = jQuery.prototype = {
94 //重定向源
95 constructor : jQuery,
96 init : function( selector, context, rootjQuery ){
97 //这个单独抽离分析
98 var match, elem, ret, doc;
99 // match-> 匹配正则结果
100 // elem -> 元素
101 // ret -->
102 // doc --> document (iframe|| !iframe)指向document针对不同情况
103 // Handle $(""), $(null), or $(undefined)
104 if ( !selector ) {
105 return this;
106 }
107
108 // Handle $(DOMElement)
109 if ( selector.nodeType ) {
110 this.context = this[0] = selector;
111 this.length = 1;
112 return this;
113 }
114
115 // The body element only exists once, optimize finding it
116 if ( selector === "body" && !context && document.body ) {
117 this.context = document;
118 this[0] = document.body;
119 this.selector = selector;
120 this.length = 1;
121 return this;
122 }
123
124 // Handle HTML strings
125 if ( typeof selector === "string" ) {
126 // Are we dealing with HTML string or an ID?
127 // 如果是正常的HTML 或ID (这里感觉可以去除空白再检查不知道作者意图)
128 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
129 // Assume that strings that start and end with <> are HTML and skip the regex check
130 match = [ null, selector, null ];
131
132 } else {
133 match = quickExpr.exec( selector );
134 }
135
136 // 是个HTML 或者是#ID 不含特殊选择
137 // Verify a match, and that no context was specified for #id
138 if ( match && (match[1] || !context) ) {
139 //简单模式
140 // HANDLE: $(html) -> $(array)
141 if ( match[1] ) {
142 //匹配到了的是HTML(context应该是空的 不知道为什么还检测了一次)
143 context = context instanceof jQuery ? context[0] : context;
144 doc = ( context ? context.ownerDocument || context : document );
145
146 // If a single string is passed in and it's a single tag
147 // just do a createElement and skip the rest
148 // 简单创建(又一个问题出现。这里我不是这样做的。我直接获取了用户的属性)
149 ret = rsingleTag.exec( selector );
150
151 if ( ret ) {
152 if ( jQuery.isPlainObject( context ) ) {
153 selector = [ document.createElement( ret[1] ) ];
154 jQuery.fn.attr.call( selector, context, true );
155
156 } else {
157 selector = [ doc.createElement( ret[1] ) ];
158 }
159 // 没什么属性的就直接做。
160 } else {
161 ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
162 selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
163 }
164
165 return jQuery.merge( this, selector );
166
167 // HANDLE: $("#id")
168 } else {
169 elem = document.getElementById( match[2] );
170 // 做了判定防止IE Opera 返回多个的BUG。
171 // Check parentNode to catch when Blackberry 4.6 returns
172 // nodes that are no longer in the document #6963
173 if ( elem && elem.parentNode ) {
174 // Handle the case where IE and Opera return items
175 // by name instead of ID
176 if ( elem.id !== match[2] ) {
177 return rootjQuery.find( selector );
178 }
179
180 // Otherwise, we inject the element directly into the jQuery object
181 this.length = 1;
182 this[0] = elem;
183 }
184
185 this.context = document;
186 this.selector = selector;
187 return this;
188 }
189 // 这里做的就是看有没有context 来选择是jquery还是context寻找DOM
190 // HANDLE: $(expr, $(...))
191 } else if ( !context || context.jquery ) {
192 return ( context || rootjQuery ).find( selector );
193
194 // HANDLE: $(expr, context)
195 // (which is just equivalent to: $(context).find(expr)
196 } else {
197 return this.constructor( context ).find( selector );
198 }
199
200 // HANDLE: $(function)
201 // Shortcut for document ready
202 } else if ( jQuery.isFunction( selector ) ) {
203 return rootjQuery.ready( selector );
204 }
205 //jQuery对象 直接转换
206 if ( selector.selector !== undefined ) {
207 this.selector = selector.selector;
208 this.context = selector.context;
209 }
210 // 转换jQuery对象。
211 return jQuery.makeArray( selector, this );
212 },
213 // 设置默认参数
214 selector: "",
215 jquery: "1.7.1",
216 length: 0,
217
218 // 定义几个方法。
219 size: function() {
220 return this.length;
221 },
222 // 从Array 继承过来的slice方法调用 对this 进行操作,从0开始。
223 toArray: function() {
224 return slice.call( this, 0 );
225 },
226 // 获取某个元素或者整体所有的元素
227 get: function( num ) {
228 return num == null ?
229
230 // Return a 'clean' array
231 this.toArray() :
232
233 // Return just the object
234 ( num < 0 ? this[ this.length + num ] : this[ num ] );
235 },
236
237 pushStack: function( elems, name, selector ) {
238 // Build a new jQuery matched element set
239 var ret = this.constructor();
240
241 if ( jQuery.isArray( elems ) ) {
242 // 如果是个数组 那么转换为 jQuery 对象
243 push.apply( ret, elems );
244 } else {
245 // 整合下当前的 jQuery 对象和传入的对象
246 jQuery.merge( ret, elems );
247 }
248
249 // Add the old object onto the stack (as a reference)
250 // 记录老对象
251 ret.prevObject = this;
252
253 ret.context = this.context;
254 //如果是用来查找某个对象 把selector 添加当前的选择参数
255 if ( name === "find" ) {
256 ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
257 } else if ( name ) {
258 //其他有该参数的情况就把原来的记录下来并记录方法和要操作的事情
259 ret.selector = this.selector + "." + name + "(" + selector + ")";
260 }
261
262 // Return the newly-formed element set
263 // 返回整理好的 jQuery 对象
264 return ret;
265 },
266
267 // 遍历,可以回调支持传参
268 each: function( callback, args ) {
269 return jQuery.each( this, callback, args );
270 },
271 // ready 事件。DOM ready 操作。
272 ready: function( fn ) {
273 // Attach the listeners
274 jQuery.bindReady();
275
276 // Add the callback
277 readyList.add( fn );
278
279 return this;
280 },
281 // 获取某个 jQuery 对象 利用自己修改后的 Array 的 slice 函数来获取某个
282 eq: function( i ) {
283 i = +i;
284 return i === -1 ?
285 this.slice( i ) :
286 this.slice( i, i + 1 );
287 },
288 first: function() {
289 return this.eq( 0 );
290 },
291
292 last: function() {
293 return this.eq( -1 );
294 },
295 // 返回新 jQuery 对象 这个对象不会对以前的对象做删改为 end 提供方便。
296 slice: function() {
297 // 参数1 转换当前的对象为数组
298 //参数2 方法是slice
299 //参数3 所有的数转换为了字符 为了方便 selector 定义
300 return this.pushStack( slice.apply( this, arguments ),
301 "slice", slice.call(arguments).join(",") );
302 },
303 // 返回修改后的 jQuery 对象
304 map: function( callback ) {
305 //jQuery.map 会对参数操作转换,
306 //把参数1 遍历调用参数2并且传递前面的遍历结果以及索引传递进去
307 return this.pushStack( jQuery.map(this, function( elem, i ) {
308 // 指向this 当前索引和对象也传进去。为什么这样传递我还真没想明白
309 return callback.call( elem, i, elem );
310 }));
311 },
312 // 返回记录未破坏时候的前个选择。
313 end: function() {
314 return this.prevObject || this.constructor(null);
315 },
316 // 使得 jQuery 可以像数组一样使用
317 push: push,
318 sort: [].sort,
319 splice: [].splice
320 };
321 // 这里是为何对 jquery.fn 扩展那么就可以使用方法的原因了
322 jQuery.fn.init.prototype = jQuery.fn;

转载于:https://www.cnblogs.com/AlfredLee/archive/2012/02/01/jQuery_fn.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值