Core: make isNumeric limited to strings and numbers
[jquery.git] / src / core.js
blob8e43547ac073490a69096e6d097218d172bdc9e7
1 define( [
2         "./var/arr",
3         "./var/document",
4         "./var/slice",
5         "./var/concat",
6         "./var/push",
7         "./var/indexOf",
8         "./var/class2type",
9         "./var/toString",
10         "./var/hasOwn",
11         "./var/support"
12 ], function( arr, document, slice, concat, push, indexOf, class2type, toString, hasOwn, support ) {
14 var
15         version = "@VERSION",
17         // Define a local copy of jQuery
18         jQuery = function( selector, context ) {
20                 // The jQuery object is actually just the init constructor 'enhanced'
21                 // Need init if jQuery is called (just allow error to be thrown if not included)
22                 return new jQuery.fn.init( selector, context );
23         },
25         // Support: Android<4.1
26         // Make sure we trim BOM and NBSP
27         rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
29         // Matches dashed string for camelizing
30         rmsPrefix = /^-ms-/,
31         rdashAlpha = /-([a-z])/g,
33         // Used by jQuery.camelCase as callback to replace()
34         fcamelCase = function( all, letter ) {
35                 return letter.toUpperCase();
36         };
38 jQuery.fn = jQuery.prototype = {
40         // The current version of jQuery being used
41         jquery: version,
43         constructor: jQuery,
45         // The default length of a jQuery object is 0
46         length: 0,
48         toArray: function() {
49                 return slice.call( this );
50         },
52         // Get the Nth element in the matched element set OR
53         // Get the whole matched element set as a clean array
54         get: function( num ) {
55                 return num != null ?
57                         // Return just the one element from the set
58                         ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
60                         // Return all the elements in a clean array
61                         slice.call( this );
62         },
64         // Take an array of elements and push it onto the stack
65         // (returning the new matched element set)
66         pushStack: function( elems ) {
68                 // Build a new jQuery matched element set
69                 var ret = jQuery.merge( this.constructor(), elems );
71                 // Add the old object onto the stack (as a reference)
72                 ret.prevObject = this;
74                 // Return the newly-formed element set
75                 return ret;
76         },
78         // Execute a callback for every element in the matched set.
79         each: function( callback ) {
80                 return jQuery.each( this, callback );
81         },
83         map: function( callback ) {
84                 return this.pushStack( jQuery.map( this, function( elem, i ) {
85                         return callback.call( elem, i, elem );
86                 } ) );
87         },
89         slice: function() {
90                 return this.pushStack( slice.apply( this, arguments ) );
91         },
93         first: function() {
94                 return this.eq( 0 );
95         },
97         last: function() {
98                 return this.eq( -1 );
99         },
101         eq: function( i ) {
102                 var len = this.length,
103                         j = +i + ( i < 0 ? len : 0 );
104                 return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
105         },
107         end: function() {
108                 return this.prevObject || this.constructor();
109         },
111         // For internal use only.
112         // Behaves like an Array's method, not like a jQuery method.
113         push: push,
114         sort: arr.sort,
115         splice: arr.splice
118 jQuery.extend = jQuery.fn.extend = function() {
119         var options, name, src, copy, copyIsArray, clone,
120                 target = arguments[ 0 ] || {},
121                 i = 1,
122                 length = arguments.length,
123                 deep = false;
125         // Handle a deep copy situation
126         if ( typeof target === "boolean" ) {
127                 deep = target;
129                 // Skip the boolean and the target
130                 target = arguments[ i ] || {};
131                 i++;
132         }
134         // Handle case when target is a string or something (possible in deep copy)
135         if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
136                 target = {};
137         }
139         // Extend jQuery itself if only one argument is passed
140         if ( i === length ) {
141                 target = this;
142                 i--;
143         }
145         for ( ; i < length; i++ ) {
147                 // Only deal with non-null/undefined values
148                 if ( ( options = arguments[ i ] ) != null ) {
150                         // Extend the base object
151                         for ( name in options ) {
152                                 src = target[ name ];
153                                 copy = options[ name ];
155                                 // Prevent never-ending loop
156                                 if ( target === copy ) {
157                                         continue;
158                                 }
160                                 // Recurse if we're merging plain objects or arrays
161                                 if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
162                                         ( copyIsArray = jQuery.isArray( copy ) ) ) ) {
164                                         if ( copyIsArray ) {
165                                                 copyIsArray = false;
166                                                 clone = src && jQuery.isArray( src ) ? src : [];
168                                         } else {
169                                                 clone = src && jQuery.isPlainObject( src ) ? src : {};
170                                         }
172                                         // Never move original objects, clone them
173                                         target[ name ] = jQuery.extend( deep, clone, copy );
175                                 // Don't bring in undefined values
176                                 } else if ( copy !== undefined ) {
177                                         target[ name ] = copy;
178                                 }
179                         }
180                 }
181         }
183         // Return the modified object
184         return target;
187 jQuery.extend( {
189         // Unique for each copy of jQuery on the page
190         expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
192         // Assume jQuery is ready without the ready module
193         isReady: true,
195         error: function( msg ) {
196                 throw new Error( msg );
197         },
199         noop: function() {},
201         isFunction: function( obj ) {
202                 return jQuery.type( obj ) === "function";
203         },
205         isArray: Array.isArray,
207         isWindow: function( obj ) {
208                 return obj != null && obj === obj.window;
209         },
211         isNumeric: function( obj ) {
213                 // As of jQuery 3.0, isNumeric is limited to
214                 // strings and numbers (primitives or objects)
215                 // that can be coerced to finite numbers (gh-2662)
216                 var type = jQuery.type( obj );
217                 return ( type === "number" || type === "string" ) &&
218                         ( obj - parseFloat( obj ) + 1 ) >= 0;
219         },
221         isPlainObject: function( obj ) {
223                 // Not plain objects:
224                 // - Any object or value whose internal [[Class]] property is not "[object Object]"
225                 // - DOM nodes
226                 // - window
227                 if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
228                         return false;
229                 }
231                 if ( obj.constructor &&
232                                 !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
233                         return false;
234                 }
236                 // If the function hasn't returned already, we're confident that
237                 // |obj| is a plain object, created by {} or constructed with new Object
238                 return true;
239         },
241         isEmptyObject: function( obj ) {
242                 var name;
243                 for ( name in obj ) {
244                         return false;
245                 }
246                 return true;
247         },
249         type: function( obj ) {
250                 if ( obj == null ) {
251                         return obj + "";
252                 }
254                 // Support: Android<4.0 (functionish RegExp)
255                 return typeof obj === "object" || typeof obj === "function" ?
256                         class2type[ toString.call( obj ) ] || "object" :
257                         typeof obj;
258         },
260         // Evaluates a script in a global context
261         globalEval: function( code ) {
262                 var script = document.createElement( "script" );
264                 script.text = code;
265                 document.head.appendChild( script ).parentNode.removeChild( script );
266         },
268         // Convert dashed to camelCase; used by the css and data modules
269         // Support: IE9-11+
270         // Microsoft forgot to hump their vendor prefix (#9572)
271         camelCase: function( string ) {
272                 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
273         },
275         nodeName: function( elem, name ) {
276                 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
277         },
279         each: function( obj, callback ) {
280                 var length, i = 0;
282                 if ( isArrayLike( obj ) ) {
283                         length = obj.length;
284                         for ( ; i < length; i++ ) {
285                                 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
286                                         break;
287                                 }
288                         }
289                 } else {
290                         for ( i in obj ) {
291                                 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
292                                         break;
293                                 }
294                         }
295                 }
297                 return obj;
298         },
300         // Support: Android<4.1
301         trim: function( text ) {
302                 return text == null ?
303                         "" :
304                         ( text + "" ).replace( rtrim, "" );
305         },
307         // results is for internal usage only
308         makeArray: function( arr, results ) {
309                 var ret = results || [];
311                 if ( arr != null ) {
312                         if ( isArrayLike( Object( arr ) ) ) {
313                                 jQuery.merge( ret,
314                                         typeof arr === "string" ?
315                                         [ arr ] : arr
316                                 );
317                         } else {
318                                 push.call( ret, arr );
319                         }
320                 }
322                 return ret;
323         },
325         inArray: function( elem, arr, i ) {
326                 return arr == null ? -1 : indexOf.call( arr, elem, i );
327         },
329         // Support: Android<4.1, PhantomJS<2
330         // push.apply(_, arraylike) throws on ancient WebKit
331         merge: function( first, second ) {
332                 var len = +second.length,
333                         j = 0,
334                         i = first.length;
336                 for ( ; j < len; j++ ) {
337                         first[ i++ ] = second[ j ];
338                 }
340                 first.length = i;
342                 return first;
343         },
345         grep: function( elems, callback, invert ) {
346                 var callbackInverse,
347                         matches = [],
348                         i = 0,
349                         length = elems.length,
350                         callbackExpect = !invert;
352                 // Go through the array, only saving the items
353                 // that pass the validator function
354                 for ( ; i < length; i++ ) {
355                         callbackInverse = !callback( elems[ i ], i );
356                         if ( callbackInverse !== callbackExpect ) {
357                                 matches.push( elems[ i ] );
358                         }
359                 }
361                 return matches;
362         },
364         // arg is for internal usage only
365         map: function( elems, callback, arg ) {
366                 var length, value,
367                         i = 0,
368                         ret = [];
370                 // Go through the array, translating each of the items to their new values
371                 if ( isArrayLike( elems ) ) {
372                         length = elems.length;
373                         for ( ; i < length; i++ ) {
374                                 value = callback( elems[ i ], i, arg );
376                                 if ( value != null ) {
377                                         ret.push( value );
378                                 }
379                         }
381                 // Go through every key on the object,
382                 } else {
383                         for ( i in elems ) {
384                                 value = callback( elems[ i ], i, arg );
386                                 if ( value != null ) {
387                                         ret.push( value );
388                                 }
389                         }
390                 }
392                 // Flatten any nested arrays
393                 return concat.apply( [], ret );
394         },
396         // A global GUID counter for objects
397         guid: 1,
399         // Bind a function to a context, optionally partially applying any
400         // arguments.
401         proxy: function( fn, context ) {
402                 var tmp, args, proxy;
404                 if ( typeof context === "string" ) {
405                         tmp = fn[ context ];
406                         context = fn;
407                         fn = tmp;
408                 }
410                 // Quick check to determine if target is callable, in the spec
411                 // this throws a TypeError, but we will just return undefined.
412                 if ( !jQuery.isFunction( fn ) ) {
413                         return undefined;
414                 }
416                 // Simulated bind
417                 args = slice.call( arguments, 2 );
418                 proxy = function() {
419                         return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
420                 };
422                 // Set the guid of unique handler to the same of original handler, so it can be removed
423                 proxy.guid = fn.guid = fn.guid || jQuery.guid++;
425                 return proxy;
426         },
428         now: Date.now,
430         // jQuery.support is not used in Core but other projects attach their
431         // properties to it so it needs to exist.
432         support: support
433 } );
435 // JSHint would error on this code due to the Symbol not being defined in ES5.
436 // Defining this global in .jshintrc would create a danger of using the global
437 // unguarded in another place, it seems safer to just disable JSHint for these
438 // three lines.
439 /* jshint ignore: start */
440 if ( typeof Symbol === "function" ) {
441         jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
443 /* jshint ignore: end */
445 // Populate the class2type map
446 jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
447 function( i, name ) {
448         class2type[ "[object " + name + "]" ] = name.toLowerCase();
449 } );
451 function isArrayLike( obj ) {
453         // Support: iOS 8.2 (not reproducible in simulator)
454         // `in` check used to prevent JIT error (gh-2145)
455         // hasOwn isn't used here due to false negatives
456         // regarding Nodelist length in IE
457         var length = !!obj && "length" in obj && obj.length,
458                 type = jQuery.type( obj );
460         if ( type === "function" || jQuery.isWindow( obj ) ) {
461                 return false;
462         }
464         return type === "array" || length === 0 ||
465                 typeof length === "number" && length > 0 && ( length - 1 ) in obj;
468 return jQuery;
469 } );