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>

輸出為:

defaults -- {"validate":false,"limit":5,"name":"foo"}
options -- {"validate":true,"name":"bar"}
settings -- {"validate":true,"limit":5,"name":"bar"}

 

參考資料:jQuery.extend的實現方式


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM