💡 아래 내용은 모던 자바스크립트 딥다이브를 공부하며 이해했던 내용을 다루고 있습니다. 혹시 틀렸거나 잘못된 정보가 있다면 알려주세요!
JS에서 객체의 프로퍼티는 단순히 이름과 값이 연결된 것이 아니라, 그 이상의 정보들을 가지고 있습니다. "그 이상의 정보들"을 우리는 프로퍼티 어트리뷰트라고 부릅니다.
let obj = { name: 'John' };
let descriptor = Object.getOwnPropertyDescriptor(obj, 'name');
console.log(descriptor);
// {value: "John", writable: true, enumerable: true, configurable: true}
Object.defineProperty(obj, 'name', { writable: false });
console.log(descriptor);
// {value: "John", writable: false, enumerable: true, configurable: true}
내부 슬롯과 내부 메서드는 객체의 '뒷단'에서 일어나는 작업들을 말합니다. 이 둘은 객체가 어떻게 동작하는지, 데이터는 어떻게 저장되고 접근되는지에 대한 규칙을 정의하는 것들입니다.
내부 슬롯: 이것은 객체의 '데이터 저장소'라고 생각할 수 있습니다. 예를 들어, 만약 객체가 숫자를 저장하고 있다면, 그 숫자는
[[Value]]
라는 내부 슬롯에 저장될 것입니다. 이런 내부 슬롯들은 코드에서 직접적으로 접근하거나 바꿀 수는 없습니다.
내부 메서드: 이것은 객체가 어떻게 동작해야 하는지를 정의하는 '규칙'입니다. 예를 들어, 객체의 특정 속성에 접근하려고 할 때, 자바스크립트는
[[Get]]
이라는 내부 메서드를 사용해서 그 속성 값을 찾아냅니다. 이런 내부 메서드들도 코드에서 직접적으로 호출할 수는 없습니다.
내부 슬롯은 접근이 불가능한 것이 원칙이지만,
[[Prototype]]
내부 슬롯은__proto__
를 통해 간접적으로 접근할 수 있따.
프로퍼티 어트리뷰트에 직접 접근할 수 없기 때문에, 접근하기 위해
Object.getOwnPropertyDescriptor
메소드를 사용하여 사용되는 객체를 프로퍼티 스크립터 객체라고 합니다.
let obj = { a: 1 };
let descriptor = Object.getOwnPropertyDescriptor(obj, 'a');
console.log(descriptor);
// {value: 1, writable: true, enumerable: true, configurable: true}
자바스크립트 객체의 프로퍼티는 크게 데이터 프로퍼티와 접근자 프로퍼티 두 가지 유형이 있습니다.
가장 일반적인 타입의 프로퍼티로, 단순한 값을 저장하는 용도로 사용됩니다. 데이터 프로퍼티는 value와 writable 두 가지 어트리뷰트를 가집니다. 아래 예제에서 a는 데이터 프로퍼티로, 값을 저장하는 역할을 합니다.
let obj = { a: 1 };
[[Value]]
: 프로퍼티가 가지고 있는 실제 값을 의미합니다. 예를 들어 let cat = { name: 'Nabi' };라고 선언했다면, 'name'이라는 프로퍼티의 [[Value]]는 'Nabi'가 됩니다.
[[Writable]]
: 프로퍼티의 값 변경 가능 여부. true면 변경 가능, false면 읽기 전용.
[[Enumerable]]
: 프로퍼티의 열거 가능 여부. true면 열거 가능, false면 열거 불가능.
[[Configurable]]
: 프로퍼티의 삭제 가능 여부, 프로퍼티 어트리뷰트의 변경 가능 여부. true면 가능, false면 불가능.
값을 저장하기보다는, get과 set 메소드를 사용하여 특정 행동을 정의하는 용도로 사용됩니다. 접근자 프로퍼티는 get과 set 두 가지 어트리뷰트를 가집니다.
let person = {
firstName: 'James',
lastName: 'Bond',
get fullName() {
return `${this.firstName} ${this.lastName}`;
},
set fullName(name) {
let parts = name.split(' ');
this.firstName = parts[0];
this.lastName = parts[1];
}
};
// fullName을 읽을 때 get 함수가 호출됩니다.
console.log(person.fullName); // 출력: "James Bond"
// fullName에 값을 할당할 때 set 함수가 호출됩니다.
person.fullName = 'John Doe';
새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나 기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의하는 것을 말합니다. 그 중에서
Object.defineProperty
,Object.defineProperties
메서드를 이용하는 것이 가장 직접적인 방법입니다.
const person = {};
Object.defineProperty(person, 'firstName', {
value: 'ABC'
});
객체의 변경을 방지하기 위한 메서드들이 존재합니다.
Object.preventExtensions(obj)
로 새로운 프로퍼티 추가를 금지시킬 수 있으며,Object.isExtensible
메서드로 확장이 가능한 객체인지 여부를 확인할 수 있습니다.
Object.seal
로 객체가 읽기와 쓰기만 가능한 상태로 변경할 수 있으며,
Object.isSealed
메서드로 밀봉된 객체인지 확인할 수 있습니다.
Object.freeze
로 읽기만 가능한 상태로 변경할 수 있으며,
Object.isFrozen
메서드로 동결된 객체인지 확인할 수 있습니다.
객체 자체를 변경할 수 없도록 만드는 것을 말합니다. 이는 위의 세 가지 메서드와는 별개로, 프로그래머가 직접 코드를 작성할 때 불변성을 유지하도록 코드를 작성하는 것입니다.