ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TIL-2024.03.24 - JS - 얕은 복사 & 깊은 복사
    > 기초/Javascript 2024. 3. 24. 19:58

     

    ------- 배경

     

    아래와 같은 원시값은 값을 복사 할 때 복사된 값을 다른 메모리에 할당 하기 때문에 원래의 값과 복사된 값이 서로에게 영향을 미치지 않음.

    • 이러한 원시값들은 모두 변경이 불가능하며, 각각의 자체적인 데이터 가짐.
    • 예를 들어, 변수에 원시값을 할당하면 변수에는 해당 원시값이 직접 저장되기에 한 변수의 값을 변경해도 다른 변수에 영향 없음. 

    (string, number, boolean, undefined, null, symbol)

    const a = 1;
    let b = a;
    
    b = 2
    
    console.log(a); //1
    console.log(b); //2

     

     

     

    하지만 참조값 (Object & Array)은 변수가 객체의 주소를 가리키는 값이기 때문에 복사된 값(주소)이 같은 값을 가리킴.

     

    // 객체
    var person = {
        name: "John",
        age: 30
    };
    
    var anotherPerson = person; // 객체 참조값 복사
    
    anotherPerson.name = "Jane"; // anotherPerson을 변경
    console.log(person.name); // 출력: "Jane" - 원본 객체도 변경됨
    
    
    // 배열
    var fruits = ["Apple", "Banana", "Orange"];
    
    var otherFruits = fruits; // 배열 참조값 복사
    
    otherFruits[0] = "Grapes"; // otherFruits를 변경
    console.log(fruits[0]); // 출력: "Grapes" - 원본 배열도 변경됨

     

    > 특징 때문에 객체를 복사하는 방법은 크게 두가지 (얕은 복사, 깊은 복사)로 나뉜다.

     

    ------- 얕은 복사 (Shallow Copy)

    • 얕은 복사는 원본 객체의 속성을 새로운 객체로 복사하지만, 그 속성들이 객체일 경우에는 참조 주소만 복사.
    • 즉, 원본 객체와 복사본 객체는 동일한 객체를 참조 >이는 복사된 객체가 원본 객체의 변경에 영향을 받을 수 있음을 의미.

     

    방법:

     

     

    1. Object Assign

    // Object Assign 
    const obj = {
      a: 1,
      b: {
        c: 2,
      },
    };
    
    const copiedObj = Object.assign({}, obj);
    
    copiedObj.b.c = 3
    
    obj === copiedObj // false
    obj.b.c === copiedObj.b.c // true

     

     

     

    2. Spread Operator

    // Spread Operator 
    const obj = {
      a: 1,
      b: {
        c: 2,
      },
    };
    
    const copiedObj = {...obj}
    
    copiedObj.b.c = 3
    
    obj === copiedObj // false
    obj.b.c === copiedObj.b.c // true

     

     

     

    2-1. 주의

    // 내가 몰랐던 부분
    
    const obj = {
      a: 1,
      b: {
        c: 2,
      },
    };
    
    const copiedObj = {...obj}
    
    copiedObj.b.c = 3
    copiedObj.a = 5
    
    console.log(copiedObj) // {a: 5, b:{c:3}}
    console.log(obj) // {a: 1, b:{c:3}}
    
    // => 여기서 
    // copiedObj.b.c = 3
    // copiedObj.a = 5
    // 한 경우 obj.b.c 는 3으로 변경되었는데 obj.a 는 변경안됨
    
    // 왜?

     

     

    이유:

    더보기

    - JS에서 Spread Operator를 사용하여 얕은 복사를 수행하면 외부 구조만 복사, 내부 객체는 원본 객체와 같은 참조를 유지.

    - 따라서 copiedObj는 obj의 복사본이지만, 내부 객체는 동일한 객체를 참조.

     

    - 여기서 copiedObj.b.c = 3를 실행하면, copiedObj의 내부 객체인 b의 c 프로퍼티가 변경.

    - 하지만 이 내부 객체 b는 원본 객체 obj와 공유되기 때문에, obj.b.c도 변경.

     

    - 그러나 copiedObj.a = 5를 실행하면, copiedObj의 a 프로퍼티를 변경하면서 새로운 값을 할당.

    - 이 작업은 obj의 외부 객체인 a 프로퍼티와는 별개의 작업이므로, obj 객체는 변경되지 않습니다.

     

    > 즉, copiedObj의 변경이 obj에 영향을 미치는 것은 내부 객체에 대한 변경일 때만 해당되며, 외부 객체에 대한 변경은 별개의 작업으로 처리됩니다.

     

    > TIL-2024.03.25 - JS - 외부객체와 내부객체 참조 (중요)

    https://heathworld.tistory.com/105

     

     

    ------- 깊은 복사 (Deep Copy)

    • 깊은 복사는 모든 단계의 객체와 속성을 완전히 복사 >  따라서 원본 객체의 변경이 복사본에 영향 없음.

     

    1. JSON.Parse(JSON.stringify(obj))

    // JSON.parse & JSON.stringify
    
    const obj = {
      a: 1,
      b: {
        c: 2,
      },
    };
    
    const copiedObj = JSON.parse(JSON.stringify(obj));
    
    copiedObj.b.c = 3
    
    obj.b.c === copiedObj.b.c //false

     

     

     

    2. lodash > cloneDeep

    const obj = {
      a: 1,
      b: {
        c: 2,
      },
    };
    
    const copiedObj = _.cloneDeep(obj);
    
    copiedObj.b.c = 3
    
    obj.b.c === copiedObj.b.c //false

     

    댓글

Designed by Tistory.