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的實現方式