TIL 2024-04-22

박요셉·2024년 4월 22일

TIL

목록 보기
11/60

내배캠에서 보내준 강의와 모던 자바스크립트를 읽었고 정리해야겠다.

  1. 얕은 복사와 깊은 복사

강의를 들으며 나에게 부족한 부분만 정리하려고 생각했는데 얕은 복사와 깊은 복사가 그것이였음.
코딩을 하게 되면 정말 많이 만나게 되는 유형인만큼 한번 더 정리해보려고 함.

객체의 불변성은 정말 중요하기에 복사를 할 때에도 신경써서 해야한다.

아래는 가변되는 객체의 예이다.

// user 객체를 생성
var user = {
	name: 'wonjang',
	gender: 'male',
};

// 이름을 변경하는 함수, 'changeName'을 정의
// 입력값 : 변경대상 user 객체, 변경하고자 하는 이름
// 출력값 : 새로운 user 객체
// 특징 : 객체의 프로퍼티(속성)에 접근해서 이름을 변경했네요! -> 가변
var changeName = function (user, newName) {
	var newUser = user;
	newUser.name = newName;
	return newUser;
};

// 변경한 user정보를 user2 변수에 할당하겠습니다.
// 가변이기 때문에 user1도 영향을 받게 될거에요.
var user2 = changeName(user, 'twojang');

// 결국 아래 로직은 skip하게 될겁니다.
if (user !== user2) {
	console.log('유저 정보가 변경되었습니다.');
}

console.log(user.name, user2.name); // twojang twojang
console.log(user === user2); // true

위의 어느 부분이 문제일까?
changeName 함수의 newUser.name = newName이다.
메모리 주소로 참조를 하게 되는 객체의 경우 위와같이 할당해주면 후에 changeName 함수를 통해 새로이 값을 할당해준다 하더라도 기존의 객체와 동일한 주소의 값이 변하게 되어버린다.

var changeName = function (user, newName) {
	return {
		name: newName,
		gender: user.gender,
	};
};

위와 같이 새로운 객체를 리턴해주어 메모리의 새 주소에 새 값을 할당해 주는 식으로 복사를 진행한다면 기존의 문제는 사라질 수 있다.
하지만 하드코딩식으로 진행되어 유지보수에 있어서 어려움을 겪을 수 있기에 얕은복사에 대해 알아보자.
얕은 복사는 쉽게말하자면 바로 아래 단계의 값만 복사하는 것이다.

//이런 패턴은 어떨까요?
var copyObject = function (target) {
	var result = {};

	// for ~ in 구문을 이용하여, 객체의 모든 프로퍼티에 접근할 수 있습니다.
	// 하드코딩을 하지 않아도 괜찮아요.
	// 이 copyObject로 복사를 한 다음, 복사를 완료한 객체의 프로퍼티를 변경하면
	// 되겠죠!?
	for (var prop in target) {
		result[prop] = target[prop];
	}
	return result;
}

위와 같이 코드를 짠다면 유지보수에 더욱 유리해질 수 있지만 아직도 문제가 있다.
객체 안의 객체를 복사하게 되었을 때 그 부분에 대해서는 불변성이 지켜지지 않는 다는 점이다.
왜일까?

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

// 더 깊은 단계에 대해서는 불변성을 유지하지 못하기 때문에 값이 같아요.
// 더 혼란스러워 지는거죠 ㅠㅠ
user.urls.portfolio = 'http://portfolio.com';
console.log(user.urls.portfolio === user2.urls.portfolio); // true

// 아래 예도 똑같아요.
user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog); // true

위의 코드를 보면 user.urls에 대해서는 불변성이 지켜지지 않고 있다.
왜냐? user 객체에 직접 속한 프로퍼티에 대해서는 복사해서 완전히 새로운 데이터가 만들어진 반면, 한 단계 더 들어간 urls의 내부 프로퍼티들은 기존 데이터를 그대로 참조하고 있기 때문이다.
그러면 해당 프로퍼티에 대해 원본과 사본이 당연히 동일한 참조형 데이터의 주소를 가리키게 될 것이기에 불변성의 법칙이 지켜지지 않는다.

어떻게 해결해야 하나? 깊은 복사를 하면된다.
깊은 복사는 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법이다.
How? 재귀를 사용하면 된다.

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;
}

함수를 위와같이 수정하게 된다면 user내부의 프로퍼티가 객체일 경우 한번더 그 내부에 대한 복사를 수행하도록 함수가 재귀할 것이다.
고로 깊은 복사가 가능해진다.

  1. 모던 자바스크립트 독서

강의를 듣다보니 모던 자바스크립트의 내용과 유사한 부분이 많았기 때문에 기왕 읽어야 될 거 독서를 하기로 마음 먹었다.
오늘 1/3만큼 읽었고 이번 달 내로 완독 할 계획이다.

profile
개발자 지망생

0개의 댓글