데이터타입 심화② | 얕은복사와 깊은복사

하영·2024년 7월 23일
0

JavaScript

목록 보기
14/29

바로 이전 포스팅이었던 데이터타입 심화에서 참조형!부분의 심화라고 볼 수 있는 오늘의 TIL
사실 완벽하게 이해되지 않았는데 지금까지 알게된 부분만 정리해두고 보충수업이나 보강을 해서 수정하며 보완할 예정이다.
이거 말고도 this나 콜백함수가 나를 기다리고 있기 때문에...🚶‍♀️‍➡️

데이터 타입 심화 - 얕은 복사, 깊은 복사

이전 포스팅에서 불변객체 예시를 보면서 마무리했는데 이 방법도 최선은 아니다.

👩🏻‍💻 불변객체의 문제점

새로운 객체를 만들기 위해 변경할 필요가 없는 프로퍼티를 하드코딩으로 입력했다.
-> 이 하드코딩이 1nn개라면?!
그래서 나온 방식이 '얕은 복사'와 '깊은 복사'이다.


05. 얕은 복사

패턴

var copyObject = function (target) {
	var result = {};

	for (var prop in target) {
		result[prop] = target[prop];
	}
	return result;
}
  • for.. in 구문으로 객체의 모든 프로퍼티에 접근했기 때문에 하드코딩을 하지 않아도 된다.
  • 이렇게 접근한 요소를 copyObject로 복사한다.
  • copyObject 객체의 프로퍼티를 복사하면 원본도 유지하고 내가 원하는 프로퍼티로 바꿀 수 있다.

적용

var user = {
	name: 'wonjang',
	gender: 'male',
};

var user2 = copyObject(user);
user2.name = 'twojang';

if (user !== user2) {
	console.log('유저 정보가 변경되었습니다.');
}

console.log(user.name, user2.name);
console.log(user === user2);

원장튜터님 이름을 바꾸고 싶었는데 이 예시만큼 직관적인게 없다..ㅋㅋㅋㅋ 원장투장..최고..

이렇게 '얕은복사'를 하고 콘솔창을 보면 아래처럼 결과가 나온다.


✅ 콘솔확인

결과를 확인하기 전에 각자 어떤 값을 담고 있는지 확인하고 싶어서 중간중간 콘솔을 추가해서 확인했다.


👩🏻‍💻 얕은복사의 문제점
얕은복사에도 문제점은 있는데 "바로 아래 단꼐의 값만 복사"한다는 점이다.
즉, 중첩된 객체의 경우 객체 안의 객체의 프로퍼티는 복사하지 못하고 주소값만 복사한다.


중첩된 객체에 얕은 복사를 했을 때

var user = {
	name: 'wonjang',
	urls: { // 중첩된 객체
		portfolio: 'http://github.com/abc',
		blog: 'http://blog.com',
		facebook: 'http://facebook.com/abc',
	}
};

var user2 = copyObject(user);

user2.name = 'twojang';

// 바로 아래 단계에 대해서는 값 달라짐
console.log(user.name === user2.name); // false

// portfolio 값 못 바꿈
user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio); // true

// blog도 동일
user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog); // true

username은 바로 아래 단계이기 때문에 얕은 복사로 가져와서 프로퍼티 값을 바꾸어도 값이 달라진다. user.name !== user2.name (user.name : 'wonjang', user2.name : 'twojang')

그러나 urls 객체의 프로퍼티를 바꾸려면 불변성을 유지하지 못해서,
useruser2 의 urls 는 값이 같다. user.urls.portfolio === user2.urls.portfolio


06. 깊은 복사

위 같은 문제점을 해결하기 위해 user.urls 프로퍼티도 불변객체로 만들어야한다.

중첩된 객체에 얕은 복사를 했을 때

var user = {
	name: 'wonjang',
	urls: {
		portfolio: 'http://github.com/abc',
		blog: 'http://blog.com',
		facebook: 'http://facebook.com/abc',
	}
};

// 1차 copy
var user2 = copyObject(user);

// 2차 copy -> 이렇게까지 해줘야만 해요..!!
user2.urls = copyObject(user.urls);

user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio); // false

user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog); // false

이렇게 한번 더 user2.urls = copyObject(user.urls); 복사를 해주어야만 결과적으로 useruser2urls 프로퍼티까지 변경할 수 있게 된다.


07. 결론 : 재귀적 수행!!

결과적으로 객체의 프로퍼티 중에서 기본형 데이터는 그대로 복사 (ex user:name) 하고
참조형 데이터는 다시 그 내부의 프로퍼티를 복사 (ex user.urls) 해야한다.
이를 재귀적 수행이라고 부른다!

🔍 재귀적 수행 : 함수느 알고리즘이 자기 자신을 호출하여 반복적으로 실행되는 것

👩🏻‍💻 이를 적용한 최종 코드

var copyObjectDeep = function(target) {
	var result = {};
	if (typeof target === 'object' && target !== null) {
		for (var prop in target) {
			result[prop] = copyObjectDeep(target[prop]);
		}
	} else {
		result = target;
	}
	return result;
}

//결과 확인
var obj = {
	a: 1,
	b: {
		c: null,
		d: [1, 2],
	}
};
var obj2 = copyObjectDeep(obj);

obj2.a = 3;
obj2.b.c = 4;
obj2.b.d[1] = 3;

console.log(obj);
console.log(obj2);

console.log 추가한 전체 코드


❓ 얕은복사와 깊은복사를 왜 사용하지?

🤨 중첩된 객체의 값을 '출력'하기 위해 깊은복사를 사용하는건가?
이 깊은복사를 왜 하는건지 궁금했다. 처음에 똑같은 user 객체로 얕은,깊은복사를 콘솔로 찍어봤는데 값이 위 사진처럼 동일했다.
얕은복사는 객체 안의 중첩된 객체의 프로퍼티를 못 가져온다 > 깊은복사를 쓴다! 라고 생각했고 중첩된 객체의 값을 '출력'하기 위해 깊은복사를 사용하는건가? 싶어서 튜터님께 질문을 드렸다.


💡 대답은 당연히 NO!!!
콘솔에 찍힌 값에 집중한 나머지 이 '복사'의 의미를 잠시 잊었다..ㅋㅋㅋ
참조형 객체를 가져와서 값을 바꿔버리면 원본 객체의 값도 바뀔 수 있으니
1) 동일한 객체를 복사해서 다른 주소에 저장하고, 2)따로 저장한 그 값을 수정해서 사용하려고 이런 얕은복사와 깊은복사를 하는 것이다!
3) 단 얕은복사는 객체 안의 객체(urls)의 프로퍼티에는 닿지 못하니까 깊은복사까지 사용하는 것!


08. JSON을 이용한 방법

완벽한 방법은 아니기 때문에 JSON을 이용한 방법이 있구나 정도만 알아두자.


참조형 객체를 복사하는 방법은 다양하다! 어느 하나 정답이 있는게 아니라 코드에 따라, 개발자에 따라 사용하는 방식이 다르다는 걸 알아두기!

그래도 헷갈리면 바로 이전 포스팅에서 왜 obj1, obj2의 데이터영역 주소를 다르게 썼는지 확인해보자!

profile
왕쪼랩 탈출 목표자의 코딩 공부기록

0개의 댓글

관련 채용 정보