본문 바로가기

기초 문법/자바스크립트

자바스크립트 객체 복사

 자바스크립트는 객체기반의 스크립트 언어이다. 객체란 여러 속성들을 하나의 변수에 저장하는 타입으로 Object 타입이라고도 한다. 이러한 객체를 복사할 때에는 얕은 복사와 깊은 복사 두 가지로 나뉘게 되는데, 각각을 살펴보고 상황에 맞춰서 사용하는 개발자가 되도록 노력하자

 

# Contents


  • 얕은 복사
  • 깊은 복사

지금부터 얕은 복사와 깊은 복사를 통해 과제를 처리하도록 하겠습니다.

 

 

# 과제


 객체 A를 통해 객체 B를 생성하고, 객체 B의 내용을 수정하겠습니다.

 

 

 

# 얕은 복사


1. Object.Assign()

Object.assign(target, ...sources)

 

 Object.Assign() 메소드는 두번째 인자 값으로 들어온 객체의 값을 첫번째에 값으로 저장합니다. 해당 구문을 통해 객체 A를 생성하고, 객체 B를 복사하여 B의 내용을 변경하도록 하겠습니다.

 

 예제 코드를 보시기 바랍니다.

let a = {
    name: "John",
    age: 10,
    friends: {
        0: "Smith",
        1: "Lyan",
    },
};

var b = Object.assign({}, a);

console.log(`------변경 전------`);
console.log(`a :  ${JSON.stringify(a)}`);
console.log(`b :  ${JSON.stringify(b)}\n`);

b.name = "Smith";
b.age = 12;
b.friends[0] = "John";

console.log(`------변경 후------`);
console.log(`a :  ${JSON.stringify(a)}`);
console.log(`b :  ${JSON.stringify(b)}\n`);

 

 결과 값은 아래와 같습니다.

 

 

 b의 name과 age가 제대로 변경되었음을 확인할 수 있습니다. 하지만 a의 friends의 0번을 보면 건들지도 않은 a의 값이 변경되어졌습니다. 왜 이런 것일까요??

 해당 함수가 얕은 복사인 이유는 객체 속의 객체를 복사하지 못하고 참조만 하기 때문입니다. 객체 B의 값을 변경하면 참조 대상인 A의 값도 변경되기 때문에 깊은 복사가 필요한 상황에서는 사용해서는 안되는 것을 파악할 수 있습니다. 

 

2. ES6 Spread

var target = { name: "Jone" }
var object = { ...target };

 

 ES6에 새로 추가된 문법 전개 연산자입니다. 배열이나 Object 형식을 전개 연산자를 통해 해당 값들을 전개시킬 수 있습니다. 이러한 방식을 통하여 값을 복사하는 것도 가능한데, 해당 전개 연산자는 Object.Assign() 함수와 마찬가지로 깊은 복사 형태로는 사용하지 않습니다. 현재 깊이 만큼 만의 복사만 처리되기 때문이죠.

 

 

# 깊은 복사


 그러면 얕은 복사의 한계점을 알고 깊은 복사를 처리하고 싶은 분들이 많이 오셨을거라 생각합니다. 깊은 복사는 여기서 크게 2가지로 나뉘어 설명하겠습니다. 먼저 첫번째 방안입니다.

 

1. Lodash의 cloneDeep

lodash를 사용하기 위해서는 lodash 프레임 워크가 설치되어 있어야 합니다. https://lodash.com/ 에서 확인하세요.

var target = _.cloneDeep(source);

 

 cloneDeep 메소드는 첫번째 인자 값으로 들어온 객체의 값 복사하여 저장합니다. 해당 구문을 통해 객체 A를 생성하고, 객체 B를 복사하여 B의 내용을 변경하도록 하겠습니다. 다음 예제는 ESM 모듈 환경에 Node.js에서 실행하였습니다.

import _ from "lodash";

let a = {
    name: "John",
    age: 10,
    friends: {
        0: "Smith",
        1: "Lyan",
    },
};

var b = _.cloneDeep(a);

console.log(`------변경 전------`);
console.log(`a :  ${JSON.stringify(a)}`);
console.log(`b :  ${JSON.stringify(b)}\n`);

b.name = "Smith";
b.age = 12;
b.friends[0] = "John";

console.log(`------변경 후------`);
console.log(`a :  ${JSON.stringify(a)}`);
console.log(`b :  ${JSON.stringify(b)}\n`);

 

결과 값은 아래와 같습니다.

 

 

얕은 복사와는 다르게 a의 내용을 변경하지 않고 참조하지 않는 상태에서 복사가 완료 되었습니다. 라이브러리를 사용한 깊은 복사를 이용하게 되면 쉽게 구현할 수 있습니다.

 

2. 직접 구현

라이브러리를 사용하지 않고 직접 구현하는 코드는 아래와 같습니다. 

function deepClone(target) {
    if (target === null || typeof target !== "object") return target;

    var res = Array.isArray(target) ? [] : {};

    for (const key in target) {
        res[key] = deepClone(target[key]);
    }

    return res;
}

 

이 함수를 사용하여 타겟을 생성 후 타겟의 속성을 변경해보도록 하겠습니다.

예제 코드는 아래와 같습니다.

let a = {
    name: "John",
    age: 10,
    friends: {
        0: "Smith",
        1: "Lyan",
    },
};

var b = deepClone(a);

console.log(`------변경 전------`);
console.log(`a :  ${JSON.stringify(a)}`);
console.log(`b :  ${JSON.stringify(b)}\n`);

b.name = "Smith";
b.age = 12;
b.friends[0] = "John";

console.log(`------변경 후------`);
console.log(`a :  ${JSON.stringify(a)}`);
console.log(`b :  ${JSON.stringify(b)}\n`);

 

이 코드를 실행한 결과 값은 아래와 같습니다. 

 

 

이처럼 라이브러리를 사용하는 방법과 함수를 직접 구현하여 깊은 복사까지 처리를 한 형태를 볼 수 있었습니다. Lodash 는 많이 사용하는 라이브러리 중 하나입니다. 함수를 직접 구현하는 것 보다는 라이브러리를 사용하여 구현하는 편이 편하고 유용하다고 생각합니다. 

 

 

 

 

'기초 문법 > 자바스크립트' 카테고리의 다른 글

[jQuery] jQuery 정리  (0) 2021.11.23
[Java] 자바로 SCP 전송  (0) 2021.09.29
[JavaScript] Decorator  (0) 2021.09.28
[JavaScript] AES128 암호화/복호화  (0) 2021.09.24
객체에서 배열, 배열에서 객체  (0) 2021.09.24