Generic jQuery.merge and safer jQuery.makeArray(nodeList).
authorRobert Katic <robert.katic@gmail.com>
Wed, 18 Nov 2009 02:26:42 +0000 (10:26 +0800)
committerJohn Resig <jeresig@gmail.com>
Wed, 25 Nov 2009 16:56:49 +0000 (00:56 +0800)
* Made jQuery.marge more generic supporting null and undefined values, and supporting array like objects as results. Fixes #5527.

* Made jQuery.makeArray(nodeList) more safer using jQuery.merge internally. Fixes #5528.

* Added a second "results" argument to jQuery.makeArray for internal usage to avoid intermediary arrays in init.

src/core.js
test/unit/core.js

index b821336..3ba2a85 100644 (file)
@@ -132,9 +132,9 @@ jQuery.fn = jQuery.prototype = {
                        this.context = selector.context;
                }
 
-               return this.setArray(jQuery.isArray( selector ) ?
-                       selector :
-                       jQuery.makeArray(selector));
+               return jQuery.isArray( selector ) ?
+                       this.setArray( selector ) :
+                       jQuery.makeArray( selector, this );
        },
 
        // Start with an empty selector
@@ -419,19 +419,16 @@ jQuery.extend({
                return (text || "").replace( rtrim, "" );
        },
 
-       makeArray: function( array ) {
-               var ret = [], i;
+       // results is for internal usage only
+       makeArray: function( array, results ) {
+               var ret = results || [];
 
                if ( array != null ) {
-                       i = array.length;
-
                        // The window, strings (and functions) also have 'length'
-                       if ( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval ) {
-                               ret[0] = array;
+                       if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval ) {
+                               push.call( ret, array );
                        } else {
-                               while ( i ) {
-                                       ret[--i] = array[i];
-                               }
+                               jQuery.merge( ret, array );
                        }
                }
 
@@ -453,12 +450,21 @@ jQuery.extend({
        },
 
        merge: function( first, second ) {
-               // We have to loop this way because IE & Opera overwrite the length
-               // expando of getElementsByTagName
-               var i = 0, elem, pos = first.length;
+               var pos, i = second.length;
 
-               while ( (elem = second[ i++ ]) != null ) {
-                       first[ pos++ ] = elem;
+               // We have to get length this way when IE & Opera overwrite the length
+               // expando of getElementsByTagName
+               if ( i && i.nodeType ) {
+                       for ( i = 0; second[i]; ++i ) {}
+               }
+               
+               pos = i + first.length;
+               
+               // Correct length for non Arrays
+               first.length = pos;
+               
+               while ( i ) {
+                       first[ --pos ] = second[ --i ];
                }
 
                return first;
index 7a2c4d6..4044bd8 100644 (file)
@@ -500,7 +500,7 @@ test("index(Object|String|undefined)", function() {
 });
 
 test("jQuery.merge()", function() {
-       expect(6);
+       expect(8);
 
        var parse = jQuery.merge;
 
@@ -514,6 +514,10 @@ test("jQuery.merge()", function() {
 
        // Fixed at [5998], #3641
        same( parse([-2,-1], [0,1,2]), [-2,-1,0,1,2], "Second array including a zero (falsy)");
+       
+       // After fixing #5527
+       same( parse([], [null, undefined]), [null, undefined], "Second array including null and undefined values");
+       same( parse({length:0}, [1,2]), {length:2, 0:1, 1:2}, "First array like");
 });
 
 test("jQuery.extend(Object, Object)", function() {
@@ -554,7 +558,7 @@ test("jQuery.extend(Object, Object)", function() {
 
        var myKlass = function() {};
        var customObject = new myKlass();
-       var optionsWithCustomObject = { foo: { date: new customObject } };
+       var optionsWithCustomObject = { foo: { date: customObject } };
        empty = {};
        jQuery.extend(true, empty, optionsWithCustomObject);
        ok( empty.foo && empty.foo.date === customObject, "Custom objects copy correctly (no methods)" );