회고록 블로그

[공부 필기] JavaScript 문법 공부 20일차 (1) 본문

2. 프로그래밍 언어 공부/JavaScript

[공부 필기] JavaScript 문법 공부 20일차 (1)

김간장 2022. 5. 12. 16:11

※ 필자는 초초초보자입니다.

※ 틀린 내용에 대한 피드백은 언제든지 환영합니다.

 

 

공부하고 있는 자료 : modern JavaScript tutorial 

https://ko.javascript.info/object-copy

 

참조에 의한 객체 복사

 

ko.javascript.info

 

✅ 참조에 의한 객체 복사

- 보통 복사하려고 할 때

- 원시값(문자열, 숫자 등)은 값 그대로 저장.할당되고 복사되지만 (값 복사)

- 객체는 참조에 의해(by reference) 저장되고 복사된다.

 

- 코드 예시

   » 아래 코드의 변수 user에는 객체의 값이 아니라 객체가 저장된 "메모리 주소"(참조값)이 저장된다.

let user = {
	name: "soySauce",
	age: 1
};

   » 만약 다른 변수에 user 변수의 값을 복사한다고하면 "참조값"이 복사된다.

 

✅ 참조에 의한 비교

- 동등 연산자(==), 일치 연산자(===)

   » 피연산자인 두 객체가 동일한 객체(참조값)인 경우 참 반환

- 비교 연산자(>, < 등)나 원시값과의 비교 시에는 객체가 원시형으로 변환된다.

   » obj1 > obj2 , obj == 5 등

   » 이런 코드를 사용하는 경우는 매우 드물다고 한다.

 

✅ 객체 복사, 병합과 Object.assign

- 객체를 복제하고 싶다면?

   » 기존 객체와 독립적이지만(객체의 참조값이 다름), 기존 객체와 똑같은 모습으로 만들고 싶을 때

   » 방법1. for ... in 연산자를 사용해서 복사

let user = {
	name: "soySauce",
	age: 1
};

let clone = {};

for (let key in user) {
	clone[key] = user[key];
}

...

// 코드출처 : 모던 자바스크립트(https://ko.javascript.info/object-copy)

   » 방법2. Object.assign을 사용

       원시형을 복제할 때는 값이 복사되지만

       객체 안에 있는 객체형을 복제하려고 할 때는 참조값이 복사된다.

      (이렇게 참조값을 복사하는 것을 "얕은 복사(shallow copy)"라고 한다.

       객체 안에 있는 객체형을 복제한다는 말이 어려운데, 이건 뒤에서 다시 보기로 하자.

Object.assgin(target, [obj1], [obj2], [obj3], ...);

// 첫번째 인수 : 목표로 하는 객체(클론할 객체)
/* 두번째 인수 이후부터 : 복사하고자 하는 객체(기존 객체들)
   두번째, 세번째, ..., n번째 객체의 프로퍼티를 첫번째 인수로 복사한다. */
// 반환값 : dest (참조값)

 

- Object.assign 예시

   » 동일한 이름을 가진 프로퍼티가 있는 경우엔 기존 값이 덮어씌워진다.

"use strict";

let user1 = {
	name: "soySauce",
	age: 1
};

let user2 = {
	name: "kim",
	age: 2
};

let user3 = {
	age: 3
};

let clone = {};

Object.assign(clone, user1, user2, user3);

console.log(clone); // clone 객체는 프로퍼티가 두 개이다. (age: 3과 name: "kim")

- target이 빈 중괄호이면, 빈 배열에 복사된다.

   » 예시

let clone2 = Object.assign({}, user1, user2, user3);

- 이렇게 복사하면, 클론한 객체와 기존 객체의 참조값은 다르다.

 

 

✅ 복사하려는 기존 객체가 원시값이 아니라면?
      어떻게 복사해야할까

- 아래와 같이 객체 안에 객체가 있다면, 이 값을 어떻게 복제해야할까

let user1 = {
	name: "soySauce",
	age: 1,
	school: {
		element: "aSchool",
		middle: "bSchool",
		high: "cSchool"
	}
};

   » 일단 프로퍼티를 출력하자.

for (let key in user1) {
	console.log(`${key} : ${user1[key]}`);
}

for (let key in user1.school) {
	console.log(`${key} : ${user1.school[key]}`);
}

 

- 단순히 Object.assign을 이용해서 user1.school을 변수 clone에 복사하는 것만으로는 부족하다.

   » Object.assign은 이 객체 안에 있는 객체를 복사할 때 얕은 복사(참조값을 복사)하기 때문이다.

   » 따라서, 같은 객체를 가리키게 될 뿐 "값"이 복사되는게 아니다.

let clone = {};

clone = Object.assign({}, user1);

console.log (clone.school === user1.school); // true (같은 school 객체를 가리키고 있기 때문에)

 

- 이 문제를 해결하기 위해서는 깊은 복사(deep cloning)를 이용해야한다.

 

✅ 깊은 복사(deep cloning)

- 다시 예시코드를 가져와보자.

let user1 = {
	name: "soySauce",
	age: 1,
	school: {
		element: "aSchool",
		middle: "bSchool",
		high: "cSchool"
	}
};

- 복사하고 싶은 곳은 변수 clone이며,

   변수 user1과 동일한 형태(프로퍼티가 원시형 2개, 객체형 1개)로 복제하는게 목표이다. 이때 (독립적인) "값"으로 복사해야한다.

let clone;

 

- 깊은 복사는 "user1[key]의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용"하는 방식이다.

   » 깊은 복사에서 사용되는 표준 알고리즘은 Structured cloning algorithm이다.

   » 프로그래머가 직접 깊은 복사 알고리즘을 구현해야한다.

 

- 사실 프로그래머가 직접 알고리즘을 구현하지 않아도

   자바스크립트 라이브러리 lodash의 메서드 "_.cloneDepp(obj)"나 structuredClone() 등을 사용하면

   깊은 복사를 할 수 있다.

 

 

※ 일단 깊은 복사를 구현해보자

- 자바스크립트 개념을 이해하기 위한 공부니까 깊은 복사를 직접 구현해보자.

 

- "user1[key]의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조를 복사해주는 재귀함수(또는 반복문)를 사용하면 된다고 한다.

function deepCopyObject(obj) {
	let clone = {}; // 빈 객체
	for (let key in obj) {
		if (typeof obj[key] === "object") { // clone[key]가 object(객체이면)
			clone[key] = {}; // clone[key] 빈 객체 만들고
			for (let key2 in obj[key]) {
				clone[key][key2] = obj[key][key2]; // 객체 안에 객체의 프로퍼티 복사
			}
		}
		else { // object가 아니라면
			clone[key] = obj[key]; // 원시타입 복사
		}
	}
	return (clone);
}

 

- 보통 반복문 보다는 편하게 재귀함수를 사용하는 경우가 많은 듯 하다.

   » 반복문을 사용하면 객체 안에 [객체 안에 객체 안에 객체 안에 ... 객체]인 경우를 고려해주지 못하기 때문인 듯 하다.

function deepCopyObject(obj) {
	let clone = {}; // 빈 객체
	for (let key in obj) {
		if (typeof obj[key] === "object") { // clone[key]가 object(객체이면)
			clone[key] = deepCopyObject(obj[key]); // 재귀함수
		}
		else { // object가 아니라면
			clone[key] = obj[key]; // 원시타입 복사
		}
	}
	return (clone);
}

 

 

 

추가 참고 자료 : https://leonkong.cc/posts/js-deep-copy.html

 

JavaScript로 Deep Copy 하는 여러 방법

JSON 객체의 메소드를 이용하거나 재귀적 함수, Lodash를 이용해 JavaScript에서 Deep Copy(깊은 복사)를 하는 방법을 알아본다

leonkong.cc

 

Comments