본문 바로가기

JavaScript

자바스크립트 새로운 객체 생성 방법

문제 원인

코드 작성 중 원본 배열을 저장해 두고 새로운 배열을 만들 일이 생겼었는데 객체의 같은 메모리의 주소값을 참조하여 복사한 데이터를 수정하면 원본 데이터도 같이 수정되는 일이 있었다.

 

문제 코드

const originalData = [
    {
        name:"김아무개",
        age:10
    },
    {
        name:"이아무개",
        age:14
    },
    {
        name:"박아무개",
        age:18
    }
]

let cloneData = originalData;
cloneData[0].age = 12;

console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)

문제 코드의 실행 결과는

이 것과 같이 cloneData의 나이를 변경 하였지만 originalData에도 반영이 된 것 을 볼 수 있다.

 

해결 방안

예상 원인으로 객체가 메모리의 같은 주소를 참조해서 그런거 같다 라고 생각을 했었는데 그 예상이 맞았고 찾아보니 이와 관련해서 깊은 복사 얕은 복사라는 용어가 있었다.

 

깊은 복사(deep copy)

주소 값이 아닌 다른 주소를 참조하여 복사하는 것 을 의미한다.

깊은 복사는 재귀 함수, JSON 객체, structuredClone(), Lodash가 있다.

 

structuredClone()

const originalData = [
    {
        name:"김아무개",
        age:10
    },
    {
        name:"이아무개",
        age:14
    },
    {
        name:"박아무개",
        age:18
    }
]

let cloneData = structuredClone(originalData);
cloneData[0].age = 12;

console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)

 

JSON 객체

const originalData = [
    {
        name:"김아무개",
        age:10
    },
    {
        name:"이아무개",
        age:14
    },
    {
        name:"박아무개",
        age:18
    }
]

let cloneData = JSON.parse(JSON.stringify(originalData));
cloneData[0].age = 12;

console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)

재귀 함수

const originalData = [
    {
        name: "김아무개",
        age: 10
    },
    {
        name: "이아무개",
        age: 14
    },
    {
        name: "박아무개",
        age: 18
    }
]
function deepCopy(object) {
    if (object === null || typeof object !== "object") {
        return object;
    }
    // 객체인지 배열인지 판단
    const clone = Array.isArray(object) ? [] : {};

    for (let idx of Object.keys(object)) {
        clone[idx] = deepCopy(object[idx]);
    }

    return clone;
}


let cloneData = deepCopy(originalData);

cloneData[0].age = 12;

console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)

Lodash

import lodash from "lodash"

const originalData = [
    {
        name: "김아무개",
        age: 10
    },
    {
        name: "이아무개",
        age: 14
    },
    {
        name: "박아무개",
        age: 18
    }
]


let cloneData = lodash.cloneDeep(originalData);

cloneData[0].age = 12;

console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)

위 예제와 같이 김아무개의 이름이 바뀌지 않는다는 것 을 알 수 있다.

 

 

얕은 복사(Shallow copy)

새로운 메모리에 할당 하는 것이 아닌 메모리 주소값을 복사하여 같은 메모리를 참조하는 것을 의미한다.

=로 복사하는 것이 여기에 속합니다.

 

splice(), 전개연산자, assign()은 = 과는 약간 다른 양상을 보이는데 

orginalData === cloneData를 했을 때 =은 true가 나왔던 반면에 splice()는 false가 나왔다.

1차원 배열은 깊은 복사가 되는 반면 1차원 배열 안에 들어있는 2차원 배열의 경우 얕은 복사가 된다.

 

splice()

const originalData = [
    {
        name:"김아무개",
        age:10
    },
    {
        name:"이아무개",
        age:14
    },
    {
        name:"박아무개",
        age:18
    }
]

let cloneData = originalData.slice();
cloneData[0].age = 12;

console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)

전개 연산자

const originalData = [
    {
        name:"김아무개",
        age:10
    },
    {
        name:"이아무개",
        age:14
    },
    {
        name:"박아무개",
        age:18
    }
]

let cloneData = [...originalData];
cloneData[0].age = 12;

console.log(originalData);
console.log(cloneData);
console.log(originalData === cloneData)
console.log(originalData[0].age === cloneData[0].age)

 

 

 

 

'JavaScript' 카테고리의 다른 글

자바스크립트 상속  (0) 2024.01.09