【jQuery源码】工具函数

  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 });

 

posted @ 2016-03-24 15:20  很好玩  阅读(226)  评论(0编辑  收藏  举报