Core: add workaround for iOS JIT error in isArrayLike
[jquery.git] / src / core.js
blob4a8b73985b3a1e443f97af2cdbf3e57518a1b432
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 ) {
19                 // The jQuery object is actually just the init constructor 'enhanced'
20                 // Need init if jQuery is called (just allow error to be thrown if not included)
21                 return new jQuery.fn.init( selector, context );
22         },
24         // Support: Android<4.1
25         // Make sure we trim BOM and NBSP
26         rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
28         // Matches dashed string for camelizing
29         rmsPrefix = /^-ms-/,
30         rdashAlpha = /-([\da-z])/gi,
32         // Used by jQuery.camelCase as callback to replace()
33         fcamelCase = function( all, letter ) {
34                 return letter.toUpperCase();
35         };
37 jQuery.fn = jQuery.prototype = {
38         // The current version of jQuery being used
39         jquery: version,
41         constructor: jQuery,
43         // The default length of a jQuery object is 0
44         length: 0,
46         toArray: function() {
47                 return slice.call( this );
48         },
50         // Get the Nth element in the matched element set OR
51         // Get the whole matched element set as a clean array
52         get: function( num ) {
53                 return num != null ?
55                         // Return just the one element from the set
56                         ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
58                         // Return all the elements in a clean array
59                         slice.call( this );
60         },
62         // Take an array of elements and push it onto the stack
63         // (returning the new matched element set)
64         pushStack: function( elems ) {
66                 // Build a new jQuery matched element set
67                 var ret = jQuery.merge( this.constructor(), elems );
69                 // Add the old object onto the stack (as a reference)
70                 ret.prevObject = this;
72                 // Return the newly-formed element set
73                 return ret;
74         },
76         // Execute a callback for every element in the matched set.
77         each: function( callback ) {
78                 return jQuery.each( this, callback );
79         },
81         map: function( callback ) {
82                 return this.pushStack( jQuery.map(this, function( elem, i ) {
83                         return callback.call( elem, i, elem );
84                 }));
85         },
87         slice: function() {
88                 return this.pushStack( slice.apply( this, arguments ) );
89         },
91         first: function() {
92                 return this.eq( 0 );
93         },
95         last: function() {
96                 return this.eq( -1 );
97         },
99         eq: function( i ) {
100                 var len = this.length,
101                         j = +i + ( i < 0 ? len : 0 );
102                 return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
103         },
105         end: function() {
106                 return this.prevObject || this.constructor(null);
107         },
109         // For internal use only.
110         // Behaves like an Array's method, not like a jQuery method.
111         push: push,
112         sort: arr.sort,
113         splice: arr.splice
116 jQuery.extend = jQuery.fn.extend = function() {
117         var options, name, src, copy, copyIsArray, clone,
118                 target = arguments[0] || {},
119                 i = 1,
120                 length = arguments.length,
121                 deep = false;
123         // Handle a deep copy situation
124         if ( typeof target === "boolean" ) {
125                 deep = target;
127                 // Skip the boolean and the target
128                 target = arguments[ i ] || {};
129                 i++;
130         }
132         // Handle case when target is a string or something (possible in deep copy)
133         if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
134                 target = {};
135         }
137         // Extend jQuery itself if only one argument is passed
138         if ( i === length ) {
139                 target = this;
140                 i--;
141         }
143         for ( ; i < length; i++ ) {
144                 // Only deal with non-null/undefined values
145                 if ( (options = arguments[ i ]) != null ) {
146                         // Extend the base object
147                         for ( name in options ) {
148                                 src = target[ name ];
149                                 copy = options[ name ];
151                                 // Prevent never-ending loop
152                                 if ( target === copy ) {
153                                         continue;
154                                 }
156                                 // Recurse if we're merging plain objects or arrays
157                                 if ( deep && copy && ( jQuery.isPlainObject(copy) ||
158                                         (copyIsArray = jQuery.isArray(copy)) ) ) {
160                                         if ( copyIsArray ) {
161                                                 copyIsArray = false;
162                                                 clone = src && jQuery.isArray(src) ? src : [];
164                                         } else {
165                                                 clone = src && jQuery.isPlainObject(src) ? src : {};
166                                         }
168                                         // Never move original objects, clone them
169                                         target[ name ] = jQuery.extend( deep, clone, copy );
171                                 // Don't bring in undefined values
172                                 } else if ( copy !== undefined ) {
173                                         target[ name ] = copy;
174                                 }
175                         }
176                 }
177         }
179         // Return the modified object
180         return target;
183 jQuery.extend({
184         // Unique for each copy of jQuery on the page
185         expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
187         // Assume jQuery is ready without the ready module
188         isReady: true,
190         error: function( msg ) {
191                 throw new Error( msg );
192         },
194         noop: function() {},
196         isFunction: function( obj ) {
197                 return jQuery.type(obj) === "function";
198         },
200         isArray: Array.isArray,
202         isWindow: function( obj ) {
203                 return obj != null && obj === obj.window;
204         },
206         isNumeric: function( obj ) {
207                 // parseFloat NaNs numeric-cast false positives (null|true|false|"")
208                 // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
209                 // subtraction forces infinities to NaN
210                 // adding 1 corrects loss of precision from parseFloat (#15100)
211                 return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;
212         },
214         isPlainObject: function( obj ) {
215                 // Not plain objects:
216                 // - Any object or value whose internal [[Class]] property is not "[object Object]"
217                 // - DOM nodes
218                 // - window
219                 if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
220                         return false;
221                 }
223                 if ( obj.constructor &&
224                                 !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
225                         return false;
226                 }
228                 // If the function hasn't returned already, we're confident that
229                 // |obj| is a plain object, created by {} or constructed with new Object
230                 return true;
231         },
233         isEmptyObject: function( obj ) {
234                 var name;
235                 for ( name in obj ) {
236                         return false;
237                 }
238                 return true;
239         },
241         type: function( obj ) {
242                 if ( obj == null ) {
243                         return obj + "";
244                 }
245                 // Support: Android<4.0 (functionish RegExp)
246                 return typeof obj === "object" || typeof obj === "function" ?
247                         class2type[ toString.call(obj) ] || "object" :
248                         typeof obj;
249         },
251         // Evaluates a script in a global context
252         globalEval: function( code ) {
253                 var script = document.createElement( "script" );
255                 script.text = code;
256                 document.head.appendChild( script ).parentNode.removeChild( script );
257         },
259         // Convert dashed to camelCase; used by the css and data modules
260         // Support: IE9-11+
261         // Microsoft forgot to hump their vendor prefix (#9572)
262         camelCase: function( string ) {
263                 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
264         },
266         nodeName: function( elem, name ) {
267                 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
268         },
270         each: function( obj, callback ) {
271                 var i = 0,
272                         length = obj.length,
273                         isArray = isArraylike( obj );
275                 if ( isArray ) {
276                         for ( ; i < length; i++ ) {
277                                 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
278                                         break;
279                                 }
280                         }
281                 } else {
282                         for ( i in obj ) {
283                                 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
284                                         break;
285                                 }
286                         }
287                 }
289                 return obj;
290         },
292         // Support: Android<4.1
293         trim: function( text ) {
294                 return text == null ?
295                         "" :
296                         ( text + "" ).replace( rtrim, "" );
297         },
299         // results is for internal usage only
300         makeArray: function( arr, results ) {
301                 var ret = results || [];
303                 if ( arr != null ) {
304                         if ( isArraylike( Object(arr) ) ) {
305                                 jQuery.merge( ret,
306                                         typeof arr === "string" ?
307                                         [ arr ] : arr
308                                 );
309                         } else {
310                                 push.call( ret, arr );
311                         }
312                 }
314                 return ret;
315         },
317         inArray: function( elem, arr, i ) {
318                 return arr == null ? -1 : indexOf.call( arr, elem, i );
319         },
321         // Support: Android<4.1, PhantomJS<2
322         // push.apply(_, arraylike) throws on ancient WebKit
323         merge: function( first, second ) {
324                 var len = +second.length,
325                         j = 0,
326                         i = first.length;
328                 for ( ; j < len; j++ ) {
329                         first[ i++ ] = second[ j ];
330                 }
332                 first.length = i;
334                 return first;
335         },
337         grep: function( elems, callback, invert ) {
338                 var callbackInverse,
339                         matches = [],
340                         i = 0,
341                         length = elems.length,
342                         callbackExpect = !invert;
344                 // Go through the array, only saving the items
345                 // that pass the validator function
346                 for ( ; i < length; i++ ) {
347                         callbackInverse = !callback( elems[ i ], i );
348                         if ( callbackInverse !== callbackExpect ) {
349                                 matches.push( elems[ i ] );
350                         }
351                 }
353                 return matches;
354         },
356         // arg is for internal usage only
357         map: function( elems, callback, arg ) {
358                 var value,
359                         i = 0,
360                         length = elems.length,
361                         isArray = isArraylike( elems ),
362                         ret = [];
364                 // Go through the array, translating each of the items to their new values
365                 if ( isArray ) {
366                         for ( ; i < length; i++ ) {
367                                 value = callback( elems[ i ], i, arg );
369                                 if ( value != null ) {
370                                         ret.push( value );
371                                 }
372                         }
374                 // Go through every key on the object,
375                 } else {
376                         for ( i in elems ) {
377                                 value = callback( elems[ i ], i, arg );
379                                 if ( value != null ) {
380                                         ret.push( value );
381                                 }
382                         }
383                 }
385                 // Flatten any nested arrays
386                 return concat.apply( [], ret );
387         },
389         // A global GUID counter for objects
390         guid: 1,
392         // Bind a function to a context, optionally partially applying any
393         // arguments.
394         proxy: function( fn, context ) {
395                 var tmp, args, proxy;
397                 if ( typeof context === "string" ) {
398                         tmp = fn[ context ];
399                         context = fn;
400                         fn = tmp;
401                 }
403                 // Quick check to determine if target is callable, in the spec
404                 // this throws a TypeError, but we will just return undefined.
405                 if ( !jQuery.isFunction( fn ) ) {
406                         return undefined;
407                 }
409                 // Simulated bind
410                 args = slice.call( arguments, 2 );
411                 proxy = function() {
412                         return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
413                 };
415                 // Set the guid of unique handler to the same of original handler, so it can be removed
416                 proxy.guid = fn.guid = fn.guid || jQuery.guid++;
418                 return proxy;
419         },
421         now: Date.now,
423         // jQuery.support is not used in Core but other projects attach their
424         // properties to it so it needs to exist.
425         support: support
428 // Populate the class2type map
429 jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),
430 function(i, name) {
431         class2type[ "[object " + name + "]" ] = name.toLowerCase();
434 function isArraylike( obj ) {
436         // Support: iOS 8.2 (not reproducible in simulator)
437         // `in` check used to prevent JIT error (gh-2145)
438         // hasOwn isn't used here due to false negatives
439         // regarding Nodelist length in IE
440         var length = "length" in obj && obj.length,
441                 type = jQuery.type( obj );
443         if ( type === "function" || jQuery.isWindow( obj ) ) {
444                 return false;
445         }
447         if ( obj.nodeType === 1 && length ) {
448                 return true;
449         }
451         return type === "array" || length === 0 ||
452                 typeof length === "number" && length > 0 && ( length - 1 ) in obj;
455 return jQuery;