본 글은 정재남님의 저서 <코어 자바스크립트>를 읽고 정리한 내용입니다.
본 글에서 사용한 메모리 이미지들은 이해를 돕기 위해 메모리를 아주 간략화한 예 입니다.
이전 포스팅에서 참조형 데이터에 대해서 알아보았다.
참조형 데이터는 가변성을 띈다. 여기서 말하는 가변
은 데이터 자체를 바꾸는 것이 아니라, 객체의 내부 프로퍼티를 변경할 때만 성립한다.
그렇다면 객체의 불변성을 확보해 주어야 할 때는 어떻게 해야 할까?
함수의 매개변수로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우가 종종 발생한다.
이번 포스팅에서는 위와 같은 경우에 어떻게 불변객체를 만들 수 있을지 알아보려고 한다.
var user = {
name: 'donghwa',
gender: 'male'
};
var changeName = function (user, newName) {
var newUser = user;
newUser.name = newName;
return newUser;
};
var user2 = changeName(user, 'john');
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.');
}
console.log(user.name, user2.name); // john, john
console.log(user === user2); // true
위 코드는 객체의 가변성으로 인한 문제점을 보여주는 간단한 예시이다.
위 코드에서는 changeName
이라는 함수를 통해서 user
의 name
을 바꾸고 그 결과를 user2
에 대입하고 있다.
그리고 유저 정보가 변경되면 로그에 출력을 하도록 코드를 작성하였지만 user와 user2는 같은 객체를 기리키고 있기 때문에 그냥 지나쳐 버린다.
예를 들어, 정보가 변경된 경우 바로 알림을 해 줘야 하는 경우에는 위와 같은 코드로는 제대로 된 기능을 할 수 없다.
서로 다른 객체를 가리키도록 해야 한다.
var user = {
name: 'donghwa',
gender: 'male'
};
var changeName = function (user, newName) {
return {
name: newName,
gender: user.gender
}
};
var user2 = changeName(user, 'john');
if (user !== user2) {
console.log('유저 정보가 변경되었습니다.'); // 유저 정보가 변경되었습니다.
}
console.log(user.name, user2.name); // donghwa, john
console.log(user === user2); // false
방법1 에서는 changeName이 새로운 객체를 반환하도록 수정했다. user와 user2는 이제 다른 객체이므로 안전하게 변경 전과 변경 후를 비교할 수 있다.
하지만 문제점도 있다. 변경될 필요가 없는 정보를 하드코딩으로 입력을 한 점이다. 이렇게 되면 객체의 속성이 많아질 수록 입력해야 하는 수고가 늘어날 것이다.
var copyObject = function (target) {
var result = {};
for (var prop in target) {
result[prop] = target[prop];
}
return result;
}
위 코드는 for...in
구문을 활용하여, target 객체의 프로퍼티를 복사하여 새로운 객체를 반환하는 방법이다. 하드코딩을 하지 않아도 된다는 점에서 방법1의 문제점을 해결했지만, 몇가지 아쉬운 점들이 있다.
모든 프로퍼티
를 복사해야 하는점, 얕은 복사
만 수행한다는 점Spread Operator
를 활용하는 방법이다. 방법 2와 비슷하지만, 일부 프로퍼티의 값을 수정하고 싶을 때 더 유용하게 쓰일 것 같다.
var myUser = {
name: 'donghwa',
gender: 'male'
};
var copyObject2 = function (target, newName) {
return {
...target,
name: newName,
}
}
var newUser = copyObject2(myUser, 'john');
console.log(newUser); // { name: 'john', gender: 'male' }
console.log(myUser === newUser); // false
이번 포스팅에서는 객체를 불변객체 처럼 쓸 수 있는 몇 가지 방법들과 한계점을 알아보았다.
위에 열거한 방법들 말고도 const
키워드와 라이브러리를 조합해 시스템 상의 제약을 거는 방법도 있지만 이번 포스팅에서는 다루지 않았다.
다음 포스팅에서는 오늘 열거한 방법들의 한계점을 보완할 수 있는 깊은 복사
에 대해 알아보도록 하겠다.