首頁  >  問答  >  主體

修改 JavaScript 物件的副本會導致原始物件發生更改

<p>我正在將 <code>objA</code> 複製到 <code>objB</code></p> <pre class="brush:php;toolbar:false;">const objA = { prop: 1 }, const objB = objA; objB.prop = 2; console.log(objA.prop); // logs 2 instead of 1</pre> <p>陣列也有相同的問題</p> <pre class="brush:php;toolbar:false;">const arrA = [1, 2, 3], const arrB = arrA; arrB.push(4); console.log(arrA.length); // `arrA` has 4 elements instead of 3.</pre> <p><br /></p>
P粉765684602P粉765684602419 天前470

全部回覆(2)我來回復

  • P粉394812277

    P粉3948122772023-08-28 17:35:35

    總而言之,為了澄清起見,有四種複製 JS 物件的方法。

    1. 普通副本。當您變更原始物件的屬性時,複製的物件的屬性也會變更(反之亦然)。
    const a = { x: 0}
    const b = a;
    b.x = 1; // also updates a.x
    
    1. 淺拷貝。原始物件和複製物件的頂級屬性將是唯一的。不過,嵌套屬性將在兩個物件之間共用。使用展開運算子 ...{}Object.assign()
    const a = { x: 0, y: { z: 0 } };
    const b = {...a}; // or const b = Object.assign({}, a);
    
    b.x = 1; // doesn't update a.x
    b.y.z = 1; // also updates a.y.z
    
    1. 深層副本。所有屬性對於原始物件和複製物件都是唯一的,甚至是嵌套屬性。對於深拷貝,請將物件序列化為 JSON 並將其解析回 JS 物件。
    const a = { x: 0, y: { z: 0 } };
    const b = JSON.parse(JSON.stringify(a)); 
    
    b.y.z = 1; // doesn't update a.y.z
    
    1. 完整深拷貝。使用上述技術,JSON 中無效的屬性值(如函數)將被丟棄。如果您需要深層複製並保留包含函數的巢狀屬性,您可能需要查看像 lodash 這樣的實用程式庫。
    import { cloneDeep } from "lodash"; 
    const a = { x: 0, y: { z: (a, b) => a + b } };
    const b = cloneDeep(a);
    
    console.log(b.y.z(1, 2)); // returns 3
    
    1. 使用Object.create()確實建立了一個新物件。這些屬性在物件之間共用(更改其中一個也會更改另一個)。與普通副本的區別在於,屬性被加入到新物件的原型 __proto__ 下。當您從不更改原始物件時,這也可以用作淺拷貝,但我建議使用上述方法之一,除非您特別需要這種行為。

    回覆
    0
  • P粉520545753

    P粉5205457532023-08-28 12:57:02

    很明顯,您對語句 var tempMyObj = myObj; 的作用有些誤解。

    在 JavaScript 中,物件是透過引用(更準確地說是引用的值)傳遞和分配的,因此 tempMyObjmyObj 都是對相同物件的參考。

    這是一個簡化的插圖,可以幫助您直觀地了解正在發生的事情

    // [Object1]<--------- myObj
    
    var tempMyObj = myObj;
    
    // [Object1]<--------- myObj
    //         ^ 
    //         |
    //         ----------- tempMyObj

    正如您在賦值後所看到的,兩個引用都指向同一個物件。

    如果您需要修改其中一個而不是另一個,則需要建立副本

    // [Object1]<--------- myObj
    
    const tempMyObj = Object.assign({}, myObj);
    
    // [Object1]<--------- myObj
    // [Object2]<--------- tempMyObj

    舊答案:

    #

    這裡有幾種建立物件副本的其他方法

    由於您已經在使用 jQuery:

    var newObject = jQuery.extend(true, {}, myObj);

    使用普通 JavaScript

    function clone(obj) {
        if (null == obj || "object" != typeof obj) return obj;
        var copy = obj.constructor();
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
        }
        return copy;
    }
    
    var newObject = clone(myObj);

    請參閱此處此處

    #

    回覆
    0
  • 取消回覆