내배캠에서 보내준 강의와 모던 자바스크립트를 읽었고 정리해야겠다.
강의를 들으며 나에게 부족한 부분만 정리하려고 생각했는데 얕은 복사와 깊은 복사가 그것이였음.
코딩을 하게 되면 정말 많이 만나게 되는 유형인만큼 한번 더 정리해보려고 함.
객체의 불변성은 정말 중요하기에 복사를 할 때에도 신경써서 해야한다.
아래는 가변되는 객체의 예이다.
// 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/3만큼 읽었고 이번 달 내로 완독 할 계획이다.