이 글은 You Don't Know JS 서적을 참고하여 작성하였습니다.
자바스크립트 함수는 호출 가능한 특성이 있는 일급 객체이다.
객체는 선언적(리터럴) 방식과 생성자 형식으로 생성할 수 있다.
// 선언적(리터럴)
const obj = {}
// 생성자
const obj = new Object();
객체 내부는 프로퍼티로 이루어져 있는데, key-value 형태로 key를 통해서 프로퍼티 값이 있는 곳을 참조할 수 있다.
const obj = {
name: '철수'
}
obj['name'];
obj.name;
여기서 주의해야 할 점은 객체(배열) 프로퍼티명은 항상 문자열이라는 것이다. 만약 문자열 이외의 숫자를 쓰더라도 우선 문자열로 변환된다. 따라서, 객체또는 배열의 프로퍼티명을 숫자와 혼용해서 사용하는 것은 권장하지 않는다.
const obj = {};
obj[true] = 'foo';
obj[1] = 'bar';
console.log(obj['true']); // foo
console.log(obj['1']); // bar
그럼 프로퍼티명을 런타임에 동적으로 설정할 수 있는 방법은 없을까?
ES6 부터는 계산된 프로퍼티명라는 기능이 추가되어, 객체 리터럴 선언의 프로퍼티명을 [표현식] 으로 구성해 활용할 수 있다.
const prefix = Math.floor(Math.random() * 100) % 2 === 1 ? 'a' : 'b';
const obj = {
// 계산된 프로퍼티명
[prefix + '_cal'] : '철수'
};
console.log('prefix', prefix);
console.log(obj['a_cal']);
console.log(obj['b_cal']);
객체 복사는 얕은 복사, 깊은 복사 두 가지 방법이 존재한다.
얕은 복사는 새로운 객체를 생성하고 기존 객체의 프로퍼티의 참조만 복사하는 방법이다. 프로퍼티의 경우에는 새로 생성하지 않고 동일한 레퍼런스를 참조하도록 한다.
깊은 복사는 새로운 객체 생성과 동시에 기존 객체의 프로퍼티까지 새로운 객체로 생성해 복사하는 방법이다. 만약 객체간에 상호 참조하고 있는 경우에는 깊은 복사가 환형 참조를 형태가 되어 무한 복사를 하게 되는 문제가 있다.
const a = {
name: 'a'
};
const b = {
name: 'b'
};
// 환영 참조
a.b = b;
b.a = a;
// 얕은 복사
function shallowCopy(obj) {
const result = {};
for (let [key, value] of Object.entries(obj)) {
result[key] = value;
}
return result;
}
// 깊은 복사
function deepCopy(obj) {
const result = {};
for (let [key, value] of Object.entries(obj)) {
if (typeof value === 'object') {
result[key] = deepCopy(value);
} else {
result[key] = value;
}
}
return result;
}
console.log(shallowCopy(a));
console.log(shallowCopy(b));
// { name: 'a', b: { name: 'b', a: { name: 'a', b: [Circular] } } }
// { name: 'b', a: { name: 'a', b: { name: 'b', a: [Circular] } } }
console.log(deepCopy(a));
console.log(deepCopy(b));
//function deepCopy(obj) {
// ^
//RangeError: Maximum call stack size exceeded
깊은 복사를 직접 구현할 수도 있지만, JSON 객체를 이용해서 JSON 문자열로 만들고, 이를 다시 객체로 역직렬화하는 방법도 하나의 대안이 될 수 있다.