아래 글은 책 🦁 코어 자바스크립트를 읽고 정리한 내용입니다.
객체 내부 프로퍼티를 변경할 때마다
➡️ 불변성 확보
객체에 변화를 가해도 원본이 그대로 남아있어야 하는 경우
ex) 정보가 바뀌었으면 알림 전송하는 경우, 바뀌기 전의 정보와 바뀐 후의 정보를 보여줘야하는 경우 등
var user = {
name: "namju",
gender: "male",
};
var changeName = function (user, newName) {
var newUser = user;
newUser.name = newName;
return newUser;
};
var user2 = changeName(user, "yun");
// 아래의 if문은 무시되어 지나침
if (user !== user2) {
console.log("유저 정보가 변경되었습니다.");
}
console.log(user.name, user2.name); // yun yun
console.log(user === user2); // true
➡️ 유저 정보가 변경되었음을 감지하지 못함!
var user = {
name: "namju",
gender: "male",
};
var changeName = function (user, newName) {
return {
name: newName,
gender: user.gender,
};
};
var user2 = changeName(user, "yun");
if (user !== user2) {
console.log("유저 정보가 변경되었습니다."); // 유저 정보가 변경되었습니다.
}
console.log(user.name, user2.name); // namju yun
console.log(user === user2); // false
➡️ 👎 객체에 프로퍼티가 많을수록 하드코딩해야하는 수고가 너무 늘어남
프로퍼티 개수에 상관 없이 모든 프로퍼티를 복사하는 함수를 만드는 것이 좋음
바로 아래 단계의 값들만 복사하는 방법
: for in
반복문으로 새 객체에 원래 객체의 프로퍼티들을 복사하는 함수
var copyObject = function (target) {
var result = {};
for (var prop in target) {
result[prop] = target[prop];
}
return result;
};
이 함수를 이용해 새로운 객체를 만들어 프로퍼티를 변경할 수 있음
var user = {
name: "namju",
gender: "male",
};
var user2 = copyObject(user);
user2.name = "yun";
if (user !== user2) {
console.log("유저 정보가 변경되었습니다."); // 유저 정보가 변경되었습니다.
}
console.log(user.name, user2.name); // namju yun
console.log(user === user2); // false
👎 이 방법의 단점
➡️ 게다가 협업하는 모든 개발자들에게 무조건 copyObject 함수를 사용하기로 합의시키는 것이 어려움!
프로토타입 체이닝
모든 객체(함수 포함)에는 프로토타입 객체가 포함되어 있음
그렇기 떄문에 얕은 복사를 한 객체는 부모(원본) 객체의 프로토타입에도 접근할 수 있어짐
(스코프 체이닝처럼 계속 상위로 가서 탐색을 하는 식)
내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법
얕은 복사 만으로는 중첩된 객체를 제대로 복사할 수 없음 (바로 아래 단계의 값들만 새로운 데이터 주소로 복사시키는 것)
var user = {
name: "namju",
info: {
hobby: "bike",
location: "seoul",
happy: true,
},
};
var user2 = copyObject(user);
user.name = "yun namju";
user.info.hobby = "read";
user.info.location = "busan";
console.log(user.name === user2.name); // false
console.log(user.info.hobby === user2.info.hobby); // true : 두 객체가 모두 변경됨
console.log(user.info.location === user2.info.location); // true : 두 객체가 모두 변경됨
한 단계 더 nesting 된 info 객체의 프로퍼티들에는 기존의 데이터를 그대로 참조하고 있는 것!
➡️ 이런 nested 된 모든 프로퍼티들에 대한 복사를 재귀적으로 수행해야 깊은 복사가 됨
객체의 깊은 복사를 수행하는 함수
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;
};
➕ hasOwnProperty
메서드를 통해 프로토타입 체이닝을 통해 상속된 프로퍼티는 복사하지 않도록 할 수 있음
➕ ES6, ES2017의 경우 Object.getOwnPropertyDescriptor
, Object.getOwnPropertyDescriptors
를 통해 getter/setter를 복사할 수 있음
✨ 깊은 복사를 하는 다른 방법 - JSON
객체를 JSON 문법의 문자열로 만들었다가 다시 JSON 객체로 만드는 것 (JSON.stringify
, JSON.parse
)
__proto__
, getter/setter는 JSON으로 변경 불가능하여 무시됨httpRequest
로 받은 데이터 등의 순수한 정보를 다룰 때 활용