Lets say the Array prototype has been augmented with some helper function:
Array.prototype.doSomething = function() { ... }
When I log out a simple array into the console ...
console.dir([1,2,3]);
... I get:
Array [3]
0: 1
1: 2
2: 3
length: 3
__proto__: Array[0]
doSomething: function()
everything looks fine so far.
But as soon as I deep clone the array using $.extend (deep clone because my actual data is more complex - an object with arrays as properties, but it happens in any case) ...
$.extend(true, [], [1,2,3]);
I suddenly get:
Array [3]
0: 1
1: 2
2: 3
doSomething: function() // ???
length: 3
__proto__: Array[0]
doSomething: function()
It looks like the prototype method has been added as an actual item of the array instance.
Does JQuery.extend not test for hasOwnProperty() before copying, or am I doing something wrong here?
Does JQuery.extend not test for hasOwnProperty() before copying
No it does not. From the source it uses a for ... in
loop to iterate over the properties of whatever is being cloned, but does not do a hasOwnProperty
check before setting the properties.
https://github.com/jquery/jquery/blob/7103d8ef47e04a4cf373abee0e8bfa9062fd616f/src/core.js#L120
jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[ 0 ] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; // Skip the boolean and the target target = arguments[ i ] || {}; i++; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { target = {}; } // Extend jQuery itself if only one argument is passed if ( i === length ) { target = this; i--; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( ( options = arguments[ i ] ) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject( copy ) || ( copyIsArray = jQuery.isArray( copy ) ) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && jQuery.isArray( src ) ? src : []; } else { clone = src && jQuery.isPlainObject( src ) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; };
Does it effect your array data? Depending on how you use the array probably not. Iterating over the array elements would still be the same, as long as you use the correct loop procedures. Meaning for(;;)
, for ... of
, or .forEach
. And doing JSON.stringify
would still give you the correct JSON.