1 //扩展工具函数
2 jQuery.extend({
3 // Unique for each copy of jQuery on the page
4 expando: "jQuery" + ( version + Math.random() ).replace( /D/g, "" ),
5
6 // Assume jQuery is ready without the ready module
7 isReady: true,
8
9 error: function( msg ) {
10 throw new Error( msg );
11 },
12
13 noop: function() {},
14
15 // See test/unit/core.js for details concerning isFunction.
16 // Since version 1.3, DOM methods and functions like alert
17 // aren't supported. They return false on IE (#2968).
18 isFunction: function( obj ) {
19 return jQuery.type(obj) === "function";
20 },
21
22 //首先判断是否支持ES5中的isArray
23 isArray: Array.isArray || function( obj ) {
24 return jQuery.type(obj) === "array";
25 },
26
27 //之前版本是obj && typeof obj === "object" && "setInterval" in obj;
28 isWindow: function( obj ) {
29 /* jshint eqeqeq: false */
30 //window对象是一个包含自己的对象 window.window....window === window;
31 return obj != null && obj == obj.window;
32 },
33
34 isNumeric: function( obj ) {
35 // parseFloat NaNs numeric-cast false positives (null|true|false|"")
36 // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
37 // subtraction forces infinities to NaN
38 // adding 1 corrects loss of precision from parseFloat (#15100)
39 //当不是数字时,(obj - parseFloat( obj ) + 1)为NaN,所以>=0也就为false
40 return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;
41 },
42
43 isEmptyObject: function( obj ) {
44 var name;
45 for ( name in obj ) {
46 return false;
47 }
48 return true;
49 },
50
51 // 检查obj是否是一个纯粹的对象(通过"{}" 或 "new Object"创建的对象)
52 // console.info( $.isPlainObject( {} ) ); // true
53 // console.info( $.isPlainObject( '' ) ); // false
54 // console.info( $.isPlainObject( document.location ) ); // true
55 // console.info( $.isPlainObject( document ) ); // false
56 // console.info( $.isPlainObject( new Date() ) ); // false
57 // console.info( $.isPlainObject( ) ); // false
58 isPlainObject: function( obj ) {
59 var key;
60
61 // Must be an Object.
62 // Because of IE, we also have to check the presence of the constructor property.
63 // Make sure that DOM nodes and window objects don't pass through, as well
64 // 必须是一个对象
65 // 因为在IE8中会抛出非法指针异常,必须检查constructor属性
66 // DOM节点和window对象,返回false
67 // obj不存在 或 非object类型 或 DOM节点 或 widnow对象,直接返回false
68 // 测试以下三中可能的情况:
69 // jQuery.type(obj) !== "object" 类型不是object,忽略
70 // obj.nodeType 认为DOM节点不是纯对象
71 // jQuery.isWindow( obj ) 认为window不是纯对象
72 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
73 return false;
74 }
75
76 try {
77 // Not own constructor property must be Object
78 // 测试constructor属性
79 // 具有构造函数constructor,却不是自身的属性(即通过prototype继承的)
80 if ( obj.constructor &&
81 !hasOwn.call(obj, "constructor") &&
82 !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
83 return false;
84 }
85 } catch ( e ) {
86 // IE8,9 Will throw exceptions on certain host objects #9897
87 return false;
88 }
89
90 // Support: IE<9
91 // Handle iteration over inherited properties before own properties.
92 if ( support.ownLast ) {
93 for ( key in obj ) {
94 return hasOwn.call( obj, key );
95 }
96 }
97
98 // Own properties are enumerated firstly, so to speed up,
99 // if last one is own, then all properties are own.
100 for ( key in obj ) {}
101
102 return key === undefined || hasOwn.call( obj, key );
103 },
104
105 type: function( obj ) {
106 if ( obj == null ) {
107 return obj + "";//转成字符串的一种方法
108 }
109 return typeof obj === "object" || typeof obj === "function" ?
110 class2type[ toString.call(obj) ] || "object" :
111 typeof obj;
112 },
113
114 // Evaluates a script in a global context
115 // Workarounds based on findings by Jim Driscoll
116 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
117 globalEval: function( data ) {
118 if ( data && jQuery.trim( data ) ) {
119 // We use execScript on Internet Explorer
120 // We use an anonymous function so that context is window
121 // rather than jQuery in Firefox
122 ( window.execScript || function( data ) {
123 window[ "eval" ].call( window, data );
124 } )( data );
125 }
126 },
127
128 // Convert dashed to camelCase; used by the css and data modules
129 // Microsoft forgot to hump their vendor prefix (#9572)
130 camelCase: function( string ) {
131 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
132 },
133
134 //判断节点名称是否相同
135 nodeName: function( elem, name ) {
136 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
137 },
138
139 // args is for internal usage only
140 //遍历对象或数组
141 each: function( obj, callback, args ) {
142 var value,
143 i = 0,
144 length = obj.length,
145 isArray = isArraylike( obj );
146
147 //如果有参数
148 if ( args ) {
149 if ( isArray ) {
150 for ( ; i < length; i++ ) {
151 value = callback.apply( obj[ i ], args );
152
153 if ( value === false ) {
154 break;
155 }
156 }
157 } else {
158 for ( i in obj ) {
159 value = callback.apply( obj[ i ], args );
160
161 if ( value === false ) {
162 break;
163 }
164 }
165 }
166
167 // A special, fast, case for the most common use of each
168 //没有参数args则调用,则调用call,上下文设置为当前遍历到的对象,参数设置为key/index和value
169 } else {
170 if ( isArray ) {
171 for ( ; i < length; i++ ) {
172 value = callback.call( obj[ i ], i, obj[ i ] );
173
174 if ( value === false ) {
175 break;
176 }
177 }
178 } else {
179 for ( i in obj ) {
180 value = callback.call( obj[ i ], i, obj[ i ] );
181
182 if ( value === false ) {
183 break;
184 }
185 }
186 }
187 }
188
189 return obj;
190 },
191
192 // Support: Android<4.1, IE<9
193 //利用正则去掉前后空格
194 trim: function( text ) {
195 return text == null ?
196 "" :
197 ( text + "" ).replace( rtrim, "" );
198 },
199
200 // results is for internal usage only
201 makeArray: function( arr, results ) {
202 var ret = results || [];
203
204 if ( arr != null ) {
205 if ( isArraylike( Object(arr) ) ) {//伪数组
206 jQuery.merge( ret,
207 typeof arr === "string" ?
208 [ arr ] : arr
209 );
210 } else {//不是数组也不是伪数组
211 push.call( ret, arr );
212 }
213 }
214
215 return ret;
216 },
217
218 //在数组中搜索指定的值,并返回其索引值,i为查找的起始位置
219 inArray: function( elem, arr, i ) {
220 var len;
221
222 if ( arr ) {
223 if ( indexOf ) {// 是否有本地化的Array.prototype.indexOf
224 return indexOf.call( arr, elem, i );
225 }
226
227 len = arr.length;
228 i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
229
230 for ( ; i < len; i++ ) {
231 // Skip accessing in sparse arrays
232 //i in arr表示arr[i]存在
233 if ( i in arr && arr[ i ] === elem ) {
234 return i;
235 }
236 }
237 }
238
239 return -1;
240 },
241
242 //将数组second合并到数组first中
243 merge: function( first, second ) {
244 var len = +second.length,
245 j = 0,
246 i = first.length;
247
248 while ( j < len ) {
249 first[ i++ ] = second[ j++ ];
250 }
251
252 // Support: IE<9
253 // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
254 //在IE9以前,类数组对象的length为NaN
255 if ( len !== len ) {
256 while ( second[j] !== undefined ) {
257 first[ i++ ] = second[ j++ ];
258 }
259 }
260
261 first.length = i;
262
263 return first;
264 },
265
266 // 过滤数组,返回新数组;callback返回true时保留;如果inv为true,callback返回false才会保留
267 grep: function( elems, callback, invert ) {
268 var callbackInverse,
269 matches = [],
270 i = 0,
271 length = elems.length,
272 callbackExpect = !invert;
273
274 // Go through the array, only saving the items
275 // that pass the validator function
276 //遍历数组,将回调函数返回值push到结果数组
277 for ( ; i < length; i++ ) {
278 callbackInverse = !callback( elems[ i ], i );
279 if ( callbackInverse !== callbackExpect ) {
280 matches.push( elems[ i ] );
281 }
282 }
283
284 return matches;
285 },
286
287 // arg is for internal usage only
288 //将数组或对象elems的元素/属性,转化成新的数组
289 map: function( elems, callback, arg ) {
290 var value,
291 i = 0,
292 length = elems.length,
293 isArray = isArraylike( elems ),
294 ret = [];
295
296 // Go through the array, translating each of the items to their new values
297 if ( isArray ) {//类数组或数组
298 for ( ; i < length; i++ ) {
299 value = callback( elems[ i ], i, arg );
300
301 if ( value != null ) {
302 ret.push( value );
303 }
304 }
305
306 // Go through every key on the object,
307 } else {//对象
308 for ( i in elems ) {
309 value = callback( elems[ i ], i, arg );
310
311 if ( value != null ) {
312 ret.push( value );
313 }
314 }
315 }
316
317 // Flatten any nested arrays
318 // 使嵌套数组变平
319 // concat:
320 // 如果某一项为数组,那么添加其内容到末尾。
321 // 如果该项目不是数组,就将其作为单个的数组元素添加到数组的末尾。
322 return concat.apply( [], ret );
323 },
324
325 // A global GUID counter for objects
326 guid: 1,
327
328 // Bind a function to a context, optionally partially applying any
329 // arguments.
330 // 代理方法:为fn指定上下文(即this)
331 proxy: function( fn, context ) {
332 var args, proxy, tmp;
333
334 //如果context是字符串格式,fn为fn[context]
335 //上下文环境设为fn
336 if ( typeof context === "string" ) {
337 tmp = fn[ context ];
338 context = fn;
339 fn = tmp;
340 }
341
342 // Quick check to determine if target is callable, in the spec
343 // this throws a TypeError, but we will just return undefined.
344 // 快速测试fn是否是可调用的(即函数)
345 // 但是这里仅返回undefined
346 if ( !jQuery.isFunction( fn ) ) {
347 return undefined;
348 }
349
350 // Simulated bind
351 args = slice.call( arguments, 2 );//从列表中去除前两个参数,即fn,context
352 proxy = function() {
353 return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
354 };
355
356 // Set the guid of unique handler to the same of original handler, so it can be removed
357 proxy.guid = fn.guid = fn.guid || jQuery.guid++;
358
359 return proxy;
360 },
361
362 now: function() {
363 return +( new Date() );
364 },
365
366 // jQuery.support is not used in Core but other projects attach their
367 // properties to it so it needs to exist.
368 support: support
369 });