js引用类型赋值,深拷贝与浅拷贝
JS中引用类型使用等号“=” 赋值,相当于把原来对象的地址拷贝一份给新的对象,这样原来旧的对象与新的对象就指向同一个地址,改变其中一个对象就会影响另外那个对象,也就是所谓的浅拷贝。例如:
var arr = ["One","Two","Three"]; var arrto = arr; arrto[1] = "test"; document.writeln("数组的原始值:" + arr + "<br />");//Export:数组的原始值:One,test,Three document.writeln("数组的新值:" + arrto + "<br />");//Export:数组的新值:One,test,Three
其实很多时候这并不是我们想要的结果,修改新对象时我们希望不要影响原来的对象。
今天我想说的是jQuery.extend()
jQuery.extend = jQuery.fn.extend = function() { var src, copyIsArray, copy, name, options, 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; };
$.extend(target,object1,objectN); 合并object1与objectN至target中,此操作会改变target的结构。
若不想改变原来对象,可以设置第一个参数为一个空对象{}: $.extend({},object1,objectN);
$.extend()第一个参数也可以为布尔类型,只是是否是深拷贝。$.extend(true,target,object1,objectN);设为true则表示深拷贝,不设默认为浅拷贝,此处只能设true,不能设false。
The merge performed by $.extend()
is not recursive by default; if a property of the first object is itself an object or array, it will be completely overwritten by a property with the same key in the second or subsequent object. The values are not merged. This can be seen in the example below by examining the value of banana. However, by passing true
for the first function argument, objects will be recursively merged.
Warning: Passing false
for the first argument is not supported.
Undefined properties are not copied. However, properties inherited from the object's prototype will be copied over. Properties that are an object constructed via new MyCustomObject(args)
, or built-in JavaScript types such as Date or RegExp, are not re-constructed and will appear as plain Objects in the resulting object or array.
On a deep
extend, Object and Array are extended, but object wrappers on primitive types such as String, Boolean, and Number are not. Deep-extending a cyclical data structure will result in an error.
For needs that fall outside of this behavior, write a custom extend method instead, or use a library like lodash.
Examples:
Example: Merge two objects, modifying the first.
1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="utf-8"> 5 <title>jQuery.extend demo</title> 6 <script src="https://code.jquery.com/jquery-1.10.2.js"></script> 7 </head> 8 <body> 9 10 <div id="log"></div> 11 12 <script> 13 var object1 = { 14 apple: 0, 15 banana: { weight: 52, price: 100 }, 16 cherry: 97 17 }; 18 var object2 = { 19 banana: { price: 200 }, 20 durian: 100 21 }; 22 23 // Merge object2 into object1 24 $.extend( object1, object2 ); 25 26 // Assuming JSON.stringify - not available in IE<8 27 $( "#log" ).append( JSON.stringify( object1 ) ); 28 </script> 29 30 </body> 31 </html>
输出为:{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}
object1.banana.price = 300; //改变object1中的banana对象的price属性为300
$( "#log" ).append( JSON.stringify( object1 ) ); //输出为 {"banana":{"price":300},"durian":100},object1的改变会影响object2
Example: Merge two objects recursively, modifying the first.
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>jQuery.extend demo</title> <script src="https://code.jquery.com/jquery-1.10.2.js"></script> </head> <body> <div id="log"></div> <script> var object1 = { apple: 0, banana: { weight: 52, price: 100 }, cherry: 97 }; var object2 = { banana: { price: 200 }, durian: 100 }; // Merge object2 into object1, recursively $.extend( true, object1, object2 ); // Assuming JSON.stringify - not available in IE<8 $( "#log" ).append( JSON.stringify( object1 ) ); </script> </body> </html>
输出为:{"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}
object1.banana.price = 300; //改变object1中的banana对象的price属性为300
$( "#log" ).append( JSON.stringify( object1 ) ); //输出为 {"banana":{"price":200},"durian":100},object1的改变不会影响object2
Example: Merge defaults and options, without modifying the defaults. This is a common plugin development pattern.
1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="utf-8"> 5 <title>jQuery.extend demo</title> 6 <script src="https://code.jquery.com/jquery-1.10.2.js"></script> 7 </head> 8 <body> 9 10 <div id="log"></div> 11 12 <script> 13 var defaults = { validate: false, limit: 5, name: "foo" }; 14 var options = { validate: true, name: "bar" }; 15 16 // Merge defaults and options, without modifying defaults 17 var settings = $.extend( {}, defaults, options ); 18 19 // Assuming JSON.stringify - not available in IE<8 20 $( "#log" ).append( "<div><b>defaults -- </b>" + JSON.stringify( defaults ) + "</div>" ); 21 $( "#log" ).append( "<div><b>options -- </b>" + JSON.stringify( options ) + "</div>" ); 22 $( "#log" ).append( "<div><b>settings -- </b>" + JSON.stringify( settings ) + "</div>" ); 23 </script> 24 25 </body> 26 </html>
输出为:
参考资料:jQuery.extend的实现方式