제육's 휘발성 코딩
article thumbnail
반응형

객체의 가변성 

const originalArr = [1, 2, 3, 4, 5];
let copiedArr = originalArr;

console.log(originalArr === copiedArr); 
copiedArr[0] = 6;
console.log(originalArr, copiedArr); // [6,2,3,4,5] , [6,2,3,4,5]
  • 위의 코드처럼 원본 객체는 그대로 두고 싶은 상황에서  복사본이 변경될 때 원본도 같이 변하는 문제점이 발생할 때가 있습니다. 이는 객체의 가변성으로 인해 생기는 문제입니다.

 

== VS ===

==은 값이 같은지만 비교하고, ===은 값과 타입이 같은지를 모두 비교합니다. 

let a = 1;
let b = "1"

console.log(a == b); // true
console.log(a === b); // false
  • 값은 같기 때문에 ==은 true이고 타입이 다르기 때문에 === 에선 false가 출력됩니다. 

 

let arrayA = [1,2,3,4];
let arrayB = [1,2,3,4];
let arrayC = arrayA;

console.log(arrayA == arrayB); // false
console.log(arrayB == arrayC); // false
console.log(arrayA == arrayC); // true
console.log(arrayA === arrayC); // true
  • 참조값 타입에선 참조하는 주솟값을 비교합니다. arrayC는 arrayA가 바라보고 있는 참조값을 복사했기 때문에 true를 반환하게 됩니다.

 

얕은 복사 (Shallow Copy)

얕은 복사는 객체의 바로 아래 단계인 1 Depth 값만 복사하는 방식입니다. 즉, 1 Depth가 넘어가면 원본과 사본이 동일한 주소를 가리키게 되어 둘 중 한 곳이라도 변경되면 같이 변경되게 됩니다. 

 

let copyArray = function(target) {
    let result = [];
    for (let prop in target) {
        result.push(target[prop]);
    }
    return result;
}

let originalArr = [1, 2, 3, 4, 5];
let copiedArr = copyArray(originalArr);

console.log(originalArr === copiedArr); 
copiedArr[0] = 6;
console.log(originalArr, copiedArr); // [1,2,3,4,5] , [6,2,3,4,5]
  • 다음과 같이 주솟값을 참조하지 않고, 값을 직접 넣어주는 방식을 사용한다면, 원본과 분리해서 배열을 복사할 수 있습니다. 

 

let originalArr = [1, 2, 3, 4, 5];
let copiedArr = originalArr.map((item) => item);

console.log(originalArr === copiedArr); 
copiedArr[0] = 6;
console.log(originalArr, copiedArr); // [1,2,3,4,5] , [6,2,3,4,5]
  • map 함수를 사용해도 얕은 복사를 통해 객체를 복사할 수 있습니다. 

 

function copyObject(target) {
    let result = {};
    for (let prop in target) {
        result[prop] = target[prop];
    }
    return result;
}

let personA = {
    name: "sasca",
    blog: {
        url: "https://sasca37.tistory.com"
    }
}

let personB = copyObject(personA);
console.log(personA, personB);
personB.name = "sasca37"; // B만 변경 - 1 Depth
personB.blog.url = "";  // A와 B 모두 변경 - 2 Depth
console.log(personA, personB);
  • 1 Depth 까지는 얕은 복사를 통해서 실제 값을 가져올 수 있지만, 2 Depth 부터는 실제 값이 아닌 주솟값을 가리키기 때문에 한쪽이 변경되면 다른 한쪽도 같이 변경됩니다.

 

깊은 복사 (Deep Copy)

깊은 복사는 객체의 모든 속성을 값으로 복사하는 것을 의미합니다. 따라서 프로퍼티가 2 Depth 이상이면서 참조형 데이터 인경우 내부 값을 재귀적으로 찾아와서 복사해주어야 합니다. 

 

function deepCopyObject(target) {
    let result = {};
    if (typeof target === 'object' && target !== null) {
        for (let prop in target) {
            result[prop] = deepCopyObject(target[prop]);
        }
    } else {
        result = target;
    }
    return result;
}
  • 다음과 같이 deepCopy를 할 수 있도록 재귀적으로 프로퍼티들을 순회하면서 값을 넣어주면 깊을 복사를 한 객체 본사본을 만들 수 있습니다. 

 

let personA = {
    name: "sasca",
    blog: {
        url: "https://sasca37.tistory.com"
    }
}

let personB = deepCopyObject(personA);
personB.name = "sasca37"; // B만 변경 - 1 Depth
personB.blog.url = "";    // B만 변경 - 2 Depth
console.log(personA, personB);
  • 재귀적으로 모든 프로퍼티에 값을 넣어주었기 때문에 2 Depth 이상에도 깊은 복사를 할 수 있어요. 

 

let personA = {
    name: "sasca",
    blog: {
        url: "https://sasca37.tistory.com"
    }
}

let personB = JSON.parse(JSON.stringify(personA));
personB.name = "sasca37"; // B만 변경
personB.blog.url = "";  // B만 변경
console.log(personA, personB);
  • 객체를 JSON 으로 변환했다가 다시 객체로 변환하면 깊은 복사를 처리할 수 있습니다. 단, 메서드나 숨겨진 프로퍼티 등은 제외됩니다. 

 

반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^