자바스크립트 객체 기초 - 1
목차
1. 객체
자바스크립트엔 일곱 가지 자료형이 있습니다. 이 중 여섯 개는 오직 하나의 데이터(문자열, 숫자 등)만 담을 수 있어 ‘원시형(primitive type)‘이라 부릅니다.
그런데 객체형은 원시형과 달리 다양한 데이터를 담을 수 있습니다. 키로 구분된 데이터 집합이나 복잡한 개체(entity)를 저장할 수 있죠. 객체는 자바스크립트 거의 모든 면에 녹아있는 개념이므로 자바스크립트를 잘 다루려면 객체를 잘 이해하고 있어야 합니다.
객체는 중괄호 {…}를 이용해 만들 수 있습니다. 중괄호 안에는 ‘키(key): 값(value)’ 쌍으로 구성된 프로퍼티(property) 를 여러 개 넣을 수 있는데, 키(‘프로퍼티 이름’이라고도 부름)엔 문자형, 값엔 모든 자료형이 허용됩니다.
빈 객체(‘빈 서랍장’)를 만드는 방법은 두 가지가 있습니다.
let user = new Object(); // '객체 생성자' 문법
let user = {}; // '객체 리터럴' 문법
1.1 리터럴과 프로퍼티
중괄호 {…} 안에는 ‘키: 값’ 쌍으로 구성된 프로퍼티가 들어갑니다.
let user = { // 객체
name: "John", // 키: "name", 값: "John"
age: 30 // 키: "age", 값: 30
};
// 프로퍼티 값 얻기
alert( user.name ); // John
alert( user.age ); // 30
프로퍼티 값엔 모든 자료형이 올 수 있습니다. 불린형 프로퍼티를 추가해보겠습니다.
user.isAdmin = true;
delete 연산자를 사용하면 프로퍼티를 삭제할 수 있습니다.
delete user.age;
여러 단어를 조합해 프로퍼티 이름을 만든 경우엔 프로퍼티 이름을 따옴표로 묶어줘야 합니다.
let user = {
name: "John",
age: 30,
"likes birds": true // 복수의 단어는 따옴표로 묶어야 합니다.
};
마지막 프로퍼티 끝에 쉼표를 붙여도 괜찮습니다.
let user = {
name: "John",
age: 30,
}
/*
이런 쉼표를 ‘trailing(길게 늘어지는)’ 혹은 ‘hanging(매달리는)’ 쉼표라고 부릅니다. 마지막 프로퍼티 끝에 쉼표를 붙여주면 모든 프로퍼티가 유사한 형태를 보이기 때문에 프로퍼티를 추가, 삭제, 이동하는 게 쉬워집니다.
*/
1.2 대괄호 표기법
여러 단어를 조합해 프로퍼티 키를 만든 경우엔, 점 표기법을 사용해 프로퍼티 값을 읽을 수 없습니다.
// 문법 에러 발생(SyntaxError: Unexpected identifier)
user.likes birds = true
점 표기법은 키가 ‘유효한 변수 식별자’인 경우에만 사용할 수 있습니다(유효한 변수 식별자가 되려면 공백이 있으면 안 됩니다).
키가 유효한 변수 식별자가 아닌 경우엔 점 표기법 대신에 ‘대괄호 표기법(square bracket notation)‘이라불리는 방법을 사용할 수 있습니다. 대괄호 표기법은 키에 어떤 문자열이 있던지 상관없이 동작합니다.
let user = {};
// set
user["likes birds"] = true;
// get
alert(user["likes birds"]); // true
// delete
delete user["likes birds"];
대괄호 표기법을 사용할 때는 대괄호 안 문자열을 따옴표로 묶어줘야 한다는 점에 주의하시기 바랍니다. 따옴표의 종류(큰따옴표, 작은따옴표)는 상관없습니다.
대괄호 표기법을 사용하면 아래 예시에서 변수를 키로 사용한 것과 같이 문자열뿐만 아니라 모든 표현식의 평가 결과를 프로퍼티 키로 사용할 수 있습니다.
let key = "likes birds";
// user["likes birds"] = true; 와 같습니다.
user[key] = true;
변수 key는 런타임에 평가되거나 사용자 입력에 따라 그 값이 변경될 수 있습니다. 어떤 경우든, 평가가 끝난 이후의 결과가 프로퍼티 키로 사용됩니다. 이를 응용하면 코드를 유연하게 작성할 수 있습니다.
let user = {
name: "John",
age: 30
};
let key = prompt("사용자의 어떤 정보를 얻고 싶으신가요?", "name");
// 변수로 접근
alert( user[key] ); // John ("name"을 입력한 경우)
그런데 점 표기법은 위와 같은 방식으로 사용할 수 없습니다.
let user = {
name: "John",
age: 30
};
let key = "name";
alert( user.key ) // undefined
1.3 계산된 프로퍼티
객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있다면, 이를 계산된 프로퍼티(computed property) 라고 부릅니다.
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {
[fruit]: 5, // 변수 fruit에서 프로퍼티 이름을 동적으로 받아 옵니다.
};
alert( bag.apple ); // fruit에 "apple"이 할당되었다면, 5가 출력됩니다.
위 예시에서 [fruit]은 프로퍼티 이름을 변수 fruit에서 가져오겠다는 것을 의미합니다.
사용자가 프롬프트 대화상자에 apple을 입력했다면 bag엔 {apple: 5}가 할당되었을 겁니다.
아래 예시는 위 예시와 동일하게 동작합니다
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {};
// 변수 fruit을 사용해 프로퍼티 이름을 만들었습니다.
bag[fruit] = 5;
두 방식 중 객체 리터럴 안에 직접 대괄호를 사용한 방식(계산된 프로퍼티를 사용한 예시)이 더 깔끔해 보이네요.
한편, 아래와 같이 대괄호 안에 복잡한 표현식을 사용하는 것도 가능합니다.
let fruit = 'apple';
let bag = {
[fruit + 'Computers']: 5 // bag.appleComputers = 5
};
대괄호 표기법은 프로퍼티 이름과 값의 제약을 없애주기 때문에 점 표기법보다 훨씬 강력합니다. 그런데 작성하기 번거롭다는 단점이 있습니다.
이런 이유로 (프로퍼티 이름이 확정된 상황이고, 이름도 단순하다면) 처음엔 점 표기법을 사용하다가 뭔가 복잡한 상황이 발생했을 때 대괄호 표기법으로 바꾸는 경우가 많습니다.
1.3.1 예약어도 프로퍼티 이름으로 사용할 수 있습니다.
for, let, return 같은 예약어는 변수명으로 사용할 수 없습니다.
하지만 객체 프로퍼티엔 이런 제약이 없습니다. 자바스크립트 예약어도 프로퍼티 키로 사용할 수 있죠.
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 6
객체 프로퍼티 이름엔 제약이 없지만, 역사적인 이유 때문에 특별 대우를 받는 이름이 하나 있습니다. 바로, __proto__입니다. 프로퍼티 이름(키)이 __proto__인 경우엔 값에 객체만 올 수 있습니다. 객체 이외의 자료는 프로퍼티 값으로 설정할 수 없습니다.
let obj = {};
obj.__proto__ = 5;
alert(obj.__proto__); // 5 대신 [object Object]가 출력됩니다.
1.4 단축 프로퍼티
실무에선 프로퍼티 값을 기존 변수에서 받아와 사용하는 경우가 종종 있습니다.
function makeUser(name, age) {
return {
name: name,
age: age
// ...등등
};
}
let user = makeUser("John", 30);
alert(user.name); // John
위 예시의 프로퍼티들은 이름과 값이 변수의 이름과 동일하네요. 이렇게 변수를 사용해 프로퍼티를 만드는 경우는 아주 흔한데, 프로퍼티 값 단축(property value shorthand) 을 사용하면 코드를 짧게 줄일 수 있습니다.
name:name 대신 name만 적어주어도 프로퍼티를 설정할 수 있죠.
function makeUser(name, age) {
return {
name, // name: name 과 같음
age // age: age 와 같음
// ...
};
}
한 객체에서 일반 프로퍼티와 단축 프로퍼티를 함께 사용하는 것도 가능합니다.
let user = {
name, // name: name 과 같음
age: 30
};
1.5 프로퍼티 존재 여부 확인하기
객체의 중요한 특징 중 하나는 존재하지 않는 프로퍼티에 접근하려 해도 에러가 발생하지 않고 undefined를 반환한다는 것입니다. 이런 특징을 응용하면 프로퍼티 존재 여부를 확인할 수 있습니다.
프로퍼티 in 객체
let user = {};
alert( user.noSuchProperty === undefined ); // true는 '프로퍼티가 존재하지 않음'을 의미합니다.
연산자 in을 사용해 프로퍼티 존재 여부를 확인할 수도 있습니다.
let user = { name: "John", age: 30 };
alert( "age" in user ); // user.age가 존재하므로 true가 출력됩니다.
alert( "blabla" in user ); // user.blabla는 존재하지 않기 때문에 false가 출력됩니다.
in 왼쪽엔 반드시 프로퍼티 이름이 와야 합니다. 프로퍼티 이름은 보통 따옴표로 감싼 문자열입니다.
1.5.1 값이 undefined인 프로퍼티에 ‘in’ 사용하기
일치 연산자를 사용해서 프로퍼티 존재 여부를 알아내는 방법(”=== undefined”)은 꽤 잘 동작합니다. 이 방법이 실패할 때도 가끔 있는데, 그럴 때는 in을 사용하면 프로퍼티 존재 여부를 제대로 판별할 수 있습니다.
프로퍼티는 존재하는데, 값에 undefined를 할당한 예시를 살펴봅시다.
let obj = {
test: undefined
};
alert( obj.test ); // 값이 `undefined`이므로, 얼럿 창엔 undefined가 출력됩니다. 그런데 프로퍼티 test는 존재합니다.
alert( "test" in obj ); // `in`을 사용하면 프로퍼티 유무를 제대로 확인할 수 있습니다(true가 출력됨).
obj.test는 실제 존재하는 프로퍼티입니다. 따라서 in 연산자는 정상적으로 true를 반환합니다.
위 예시같이 프로퍼티 값이 undefined인 경우는 흔치 않습니다.undefined는 변수는 정의되어 있으나 값이 할당되지 않은 경우에 쓰이죠. 값을 ‘알 수 없거나(unknown)’ 값이 ‘비어 있다는(empty)’ 것을 나타낼 때는 주로 null을 사용합니다. 위 예시에서 in 연산자는 자리에 어울리지 않는 초대손님처럼 보이네요.
1.6 ‘for…in’ 반복문
for..in 반복문을 사용하면 객체의 모든 키를 순회할 수 있습니다.
문법 :
for (key in object) {
// 각 프로퍼티 키(key)를 이용하여 본문(body)을 실행합니다.
}
let user = {
name: "John",
age: 30,
isAdmin: true
};
for (let key in user) {
// 키
alert( key ); // name, age, isAdmin
// 키에 해당하는 값
alert( user[key] ); // John, 30, true
}
변수명(let key)은 자유롭게 정할 수 있습니다. ‘for (let prop in obj)‘같이 key 말고 다른 변수명을 사용해도 괜찮습니다.
1.7 객체 정렬 방식
객체는 ‘특별한 방식으로 정렬’되죠. 정수 프로퍼티(integer property)는 자동으로 정렬되고, 그 외의 프로퍼티는 객체에 추가한 순서 그대로 정렬됩니다.
let codes = {
"49": "독일",
"41": "스위스",
"44": "영국",
// ..,
"1": "미국"
};
for (let code in codes) {
alert(code); // 1, 41, 44, 49
}
반면, 키가 정수가 아닌 경우엔 작성된 순서대로 프로퍼티가 나열됩니다. 예시를 살펴봅시다.
let user = {
name: "John",
surname: "Smith"
};
user.age = 25; // 프로퍼티를 하나 추가합니다.
// 정수 프로퍼티가 아닌 프로퍼티는 작성된 순서대로 나열됩니다.
for (let prop in user) {
alert( prop ); // name, surname, age
}
위 예시에서 49(독일 나라 번호)를 가장 위에 출력되도록 하려면 나라 번호가 정수로 취급되지 않도록 속임수를 쓰면 됩니다. 각 나라 번호 앞에 ”+“를 붙여봅시다.
let codes = {
"+49": "독일",
"+41": "스위스",
"+44": "영국",
// ..,
"+1": "미국"
};
for (let code in codes) {
alert( +code ); // 49, 41, 44, 1
}
1.7.1 정수 프로퍼티? 그게 뭔가요?
‘정수 프로퍼티’라는 용어는 변형 없이 정수에서 왔다 갔다 할 수 있는 문자열을 의미합니다.
// 함수 Math.trunc는 소수점 아래를 버리고 숫자의 정수부만 반환합니다.
alert( String(Math.trunc(Number("49"))) ); // '49'가 출력됩니다. 기존에 입력한 값과 같으므로 정수 프로퍼티가 될 수 있습니다.
alert( String(Math.trunc(Number("+49"))) ); // '49'가 출력됩니다. 기존에 입력한 값(+49)과 다르므로 정수 프로퍼티가 될 수 없습니다.
alert( String(Math.trunc(Number("1.2"))) ); // '1'이 출력됩니다. 기존에 입력한 값(1.2)과 다르므로 정수 프로퍼티가 될 수 없습니다.
1.8 참조에 의한 복사
객체와 원시 타입의 근본적인 차이 중 하나는 객체는 ‘참조에 의해(by reference)’ 저장되고 복사된다는 것입니다.
원시값(문자열, 숫자, 불린 값)은 ‘값 그대로’ 저장/할당되고 복사되는 반면에 말이죠.
let message = "Hello!";
let phrase = message;
두 개의 독립된 변수에 각각 문자열 “Hello!”가 저장되었네요.
그런데 객체의 동작방식은 이와 다릅니다.
변수에 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어있는 ‘메모리 주소’인 객체에 대한 ‘참조 값’이 저장됩니다.
user에 객체를 할당할 때 무슨 일이 일어나는지 이해해봅시다.
let user = {
name: "John"
};
객체는 메모리 내 어딘가에 저장되고, 변수 user엔 객체를 ‘참조’할 수 있는 값이 저장되죠.
객체가 할당된 변수를 복사할 땐 객체의 참조 값이 복사됩니다. 객체는 복제되지 않습니다.
객체를 서랍장에 비유하면 변수는 서랍장을 열 수 있는 열쇠라고 비유할 수 있습니다. 변수를 복사하면 똑같은 서랍장이 하나 더 만들어 지는 게 아니라 똑같은 열쇠가 하나 더 만들어집니다.
let user = { name: "John" };
let admin = user; // 참조값이 복사됨
서랍장을 열 수 있는 열쇠(변수)가 두 개가 되었으므로 서랍장 안 내용물을 확인하거나 변경할 때 어느 변수를 사용해도 무방합니다.
let user = { name: 'John' };
let admin = user;
admin.name = 'Pete'; // 'admin' 참조 값에 의해 변경됨
alert(user.name); // 'Pete'가 출력됨. 'user' 참조 값을 이용해 변경사항을 확인함
1.9 참조에 의한 비교
객체 비교 시 동등 연산자 ==와 일치 연산자 ===는 동일하게 동작합니다.
비교 시 피연산자인 두 객체가 동일한 객체인 경우에만 참이 반환되죠.
두 변수가 같은 객체를 참조하는 예시를 살펴봅시다. 일치/동등 비교시 참이 반환됩니다.
객체 비교 시 동등 연산자 ==와 일치 연산자 ===는 동일하게 동작합니다.
비교 시 피연산자인 두 객체가 동일한 객체인 경우에만 참이 반환되죠.
두 변수가 같은 객체를 참조하는 예시를 살펴봅시다. 일치/동등 비교시 참이 반환됩니다.
다른 예시를 살펴봅시다. 두 객체 모두 비어있다는 점에서 같아 보이지만, 독립된 객체이기 때문에 일치/동등 비교하면 거짓이 반환됩니다.
let a = {};
let b = {}; // 독립된 두 객체
alert( a == b ); // false
obj1 > obj2 같은 대소 비교나 obj == 5 같은 원시값과의 비교에선 객체가 원시형으로 변환됩니다. 객체가 어떻게 원시형으로 변하는지에 대해선 곧 학습할 예정인데, 이러한 비교(객체끼리의 대소 비교나 원시값과 객체를 비교하는 것)가 필요한 경우는 매우 드물긴 합니다. 대게 코딩 실수 때문에 이런 비교가 발생합니다.
1.10 const 객체
const로 선언한 객체는 변경이 가능합니다.
const user = {
name: "John"
};
user.age = 25; // (*)
alert(user.age); // 25
많은 분이 ()로 표시한 줄에서 에러가 날 것이라고 예상하셨을 겁니다. 하지만 에러는 발생하지 않습니다. 에러가 발생하지 않는 이유는 const는 오직 user에 저장된 값(한 객체에 대한 참조 값)만 고정하기 때문입니다. user는 한 객체에 대한 참조 값만 저장하고 있기 때문에 ()로 표시한 줄에선 객체 내부에 접근하기만 하고 user를 재정의하지 않습니다.
const는 user를 다른 것으로 덮어씌우려 할 때 에러를 발생시킵니다. 예시를 보시죠.
const user = {
name: "John"
};
// TypeError: Assignment to constant variable.
user = {
name: "Pete"
};
1.11 객체 복사와 병합
객체를 복제하고 싶다면 어떻게 해야 할까요? 기존에 있던 객체와 똑같으면서 독립적인 객체를 만들고 싶다면 말이죠.
사실 객체를 복제해야 할 일은 거의 없습니다. 참조에 의한 복사로 해결 가능한 일이 대다수이죠.
정말 복제가 필요한 상황이라면 새로운 객체를 만든 다음 기존 객체의 프로퍼티들을 순회해 원시 수준까지 프로퍼티를 복사해 객체를 복제하면 됩니다.
let user = {
name: "John",
age: 30
};
let clone = {}; // 새로운 빈 객체
// 빈 객체에 user 프로퍼티 전부를 복사해 넣습니다.
for (let key in user) {
clone[key] = user[key];
}
// 이제 clone은 완전히 독립적인 복제본이 되었습니다.
clone.name = "Pete"; // clone의 데이터를 변경합니다.
alert( user.name ); // 기존 객체에는 여전히 John이 있습니다.
Object.assign를 사용해 객체를 복제하는 방법도 있습니다.
Object.assign(dest, [src1, src2, src3...])
- 인수 dest 와 src1, …, srcN 는 객체입니다. …은 필요에 따라 얼마든지 많은 객체를 인수로 사용할 수 있다는 것을 나타냅니다.
- 객체 src1, …, srcN의 프로퍼티를 dest에 복사합니다. dest를 제외한 인수(객체) 모두의 프로퍼티가 첫 번째 인수(객체)로 복사됩니다. 그리고 dest를 반환합니다.
assign 메서드를 사용해 여러 객체를 하나로 병합한 예시를 살펴봅시다.
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// permissions1과 permissions2의 프로퍼티를 user로 복사합니다.
Object.assign(user, permissions1, permissions2);
// user = { name: "John", canView: true, canEdit: true }
복사된 프로퍼티를 받는 객체(user)에 동일한 이름을 가진 프로퍼티가 있으면 기존 값을 덮어씁니다.
반복문 대신 Object.assign을 사용하면 객체를 간단하게 복사할 수도 있습니다.
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
지금까진 user의 모든 프로퍼티가 원시값인 경우만 가정했습니다. 그런데 프로퍼티는 다른 객체에 대한 참조 값일 수도 있습니다. 이 경우는 어떻게 해야 할까요?
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
alert( user.sizes.height ); // 182
clone.sizes = user.sizes로 프로퍼티를 복사하는 것만으론 객체를 복제할 수 없습니다. user.sizes는 객체이기 때문에 참조 값이 복사되기 때문입니다. clone.sizes = user.sizes로 프로퍼티를 복사하면 clone과 user는 같은 sizes를 공유하게 됩니다.
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, 같은 객체입니다.
// user와 clone는 sizes를 공유합니다.
user.sizes.width++; // 한 객체에서 프로퍼티를 변경합니다.
alert(clone.sizes.width); // 51, 다른 객체에서 변경 사항을 확인할 수 있습니다.
이 문제를 해결하려면 user[key]의 각 값을 검사하면서 그 값이 객체라면 객체의 구조도 복사해주는 반복문을 사용해야 합니다. 이를 ‘깊은 복사(deep cloning)‘라고 부릅니다.
깊은 복사 시 사용되는 표준 알고리즘, Structured cloning algorithm을 사용하면 위 사례를 비롯한 다양한 상황에서 객체를 복제할 수 있습니다. 자바스크립트 라이브러리 lodash의 메서드, _.cloneDeep(obj)을 사용하면 이 알고리즘을 직접 구현하지 않고도 깊은 복사를 처리할 수 있으므로 참고하시기 바랍니다.
1.12 객체 요약
객체는 몇 가지 특수한 기능을 가진 연관 배열(associative array)입니다.
객체는 프로퍼티(키-값 쌍)를 저장합니다.
- 프로퍼티 키는 문자열이나 심볼(Symbol)이어야 합니다. 보통 문자열을 사용합니다.
- 값은 어떤 자료형도 가능합니다.
아래와 같은 방법을 사용하면 프로퍼티에 접근할 수 있습니다.
- 점 표기법: obj.property
- 대괄호 표기법 obj[“property”]. 대괄호 표기법을 사용하면 obj[varWithKey]같이 변수에서 키를 가져올 수 있습니다.
객체엔 다음과 같은 추가 연산자를 사용할 수 있습니다.
- 프로퍼티를 삭제하고 싶을 때: delete obj.prop
- 해당 key를 가진 프로퍼티가 객체 내에 있는지 확인하고자 할 때: “key” in obj
- 프로퍼티를 나열할 때: for (let key in obj)
객체는 참조에 의해 할당되고 복사됩니다. 변수엔 ‘객체’ 자체가 아닌 메모리상의 주소인 ‘참조’가 저장됩니다. 객체가 할당된 변수를 복사하거나 함수의 인자로 넘길 때 객체가 아닌 객체의 참조가 전달되죠. 복사된 참조를 이용한 모든 작업(프로퍼티 추가/삭제 등)은 동일한 객체를 대상으로 이뤄집니다.
객체를 복제하려면 Object.assign이나 _.cloneDeep(obj)를 사용하면 됩니다.
지금까진 ‘순수 객체(plain object)‘라 불리는 일반 객체(object)에 대해 학습했습니다.
자바스크립트에는 일반 객체 이외에도 다양한 종류의 객체가 있습니다.
- Array : 정렬된 데이터 컬렉션을 저장할 때 쓰임
- Date : 날짜와 시간 정보를 저장할 때 쓰임
- Error : 에러 정보를 저장할 때 쓰임
- 기타 등등
각 객체마다 고유의 기능을 제공하는데, 이에 대해선 추후 학습해 보도록 하겠습니다. 사람들은 종종 ‘Array 타입’이나 ‘Date 타입’이라는 용어를 쓰곤 합니다. 사실 Array와 Date는 독립적인 자료형이 아니라 ‘객체’형에 속합니다. 객체에 다양한 기능을 넣어 확장한 또 다른 객체이죠.
2. 가비지 컬렉션
요약
- 가비지 컬렉션은 엔진이 자동으로 수행하므로 개발자는 이를 억지로 실행하거나 막을 수 없습니다.
- 객체는 도달 가능한 상태일 때 메모리에 남습니다.
- 참조된다고 해서 도달 가능한 것은 아닙니다. 서로 연결된 객체들도 도달 불가능할 수 있습니다. 모던 자바스크립트 엔진은 좀 더 발전된 가비지 컬렉션 알고리즘을 사용합니다.
어떤 알고리즘을 사용하는지 궁금하다면 ‘The Garbage Collection Handbook: The Art of Automatic Memory Management’(저자 – R. Jones et al)를 참고하시기 바랍니다.
저 수준(low-level) 프로그래밍에 익숙하다면, A tour of V8: Garbage Collection을 읽어보세요. V8 가비지 컬렉터에 대한 자세한 내용을 확인해 볼 수 있습니다.
V8 공식 블로그에도 메모리 관리 방법 변화에 대한 내용이 올라옵니다. 가비지 컬렉션을 심도 있게 학습하려면 V8 내부구조를 공부하거나 V8 엔지니어로 일했던 Vyacheslav Egorov의 블로그를 읽는 것도 좋습니다. 여러 엔진 중 ‘V8’ 엔진을 언급하는 이유는 인터넷에서 관련 글을 쉽게 찾을 수 있기 때문입니다. V8과 타 엔진들은 동작 방법이 비슷한데, 가비지 컬렉션 동작 방식에는 많은 차이가 있습니다.
저 수준 최적화가 필요한 상황이라면, 엔진에 대한 조예가 깊어야 합니다. 먼저 자바스크립트에 익숙해진 후에 엔진에 대해 학습하는 것을 추천해 드립니다.