프로퍼티 어트리뷰트
팀 러버덕 by Hoon
내부 슬롯과 내부 메서드
const myObject = {}
myObject.[[Prototype]] // Uncaught Syntax Error!
myObject.__proto__ // Object.prototype
내부 슬롯과 내부 메서드
프로퍼티 어트리뷰트
- 프로퍼티의 값
- 갱신 가능 여부
- 열거 가능 여부
- 재정의 가능 여부
내부 슬롯과 내부 메서드
const person = {
name: 'hoon'
}
// person 객체의 name 프로퍼티의 어트리뷰트 출력
console.log(Object.getOwnPropertyDescriptor(person, "name"))
/*
{
configurable: true
enumerable: true
value: "hoon"
writable: true
[[Prototype]]: Object
}
*/
데이터 프로퍼티와 접근자 프로퍼티
데이터 프로퍼티
- 키와 값으로 구성된 프로퍼티
- 우리가 살펴본 모든 프로퍼티들
접근자 프로퍼티
- 자체적으로 값이 없음
- 접근자 함수로 구성된 프로퍼티
데이터 프로퍼티
프로퍼티 어트리뷰트 | 프로퍼티 디스크립터 객체의 프로퍼티 | 설명 |
---|---|---|
[[Value]] | value | - 프로퍼티 키를 통해 프로퍼티 값에 접근하면 반환되는 값 - 프로퍼티 키를 통해 값을 변경하면, [[Value]] 에 값을 재할당 프로퍼티가 존재하지 않으면 자동으로 생성한 뒤, 생성된 프로퍼티의 [[Value]] 에 값을 저장 |
[[Writable]] | writable | - 프로퍼티 값의 변경 가능 여부를 표현 (불리언) - [[Writable]] 값이 false 인 경우, [[Value]] 값을 변경할 수 없는 read-only 프로퍼티로 설정된다 |
[[Enumerable]] | enumerable | - 프로퍼티 열거 가능 여부를 표현 (불리언) - [[Enumerable]] 값이 false 인 경우, 해당 프로퍼티의 값은 열거할 수 없다 (for .. of / for .. in 사용 불가능) |
[[Configurable]] | configurable | - 프로퍼티의 재정의 가능 여부를 표현 (불리언) - [[Configuratlbe]] 의 값이 false인 경우, 해당 프로퍼티 값 변경 또는 삭제가 금지된다 - [[Configurable]] 이 false여도, [[Value]] 변경과 [[Writable]] 값만 true로 설정할 수 있다 |
데이터 프로퍼티
const person = {
name: 'hoon'
}
// person 객체의 name 프로퍼티의 어트리뷰트 출력
console.log(Object.getOwnPropertyDescriptor(person, "name"))
/*
{
value: "hoon"
writable: true
enumerable: true
configurable: true
[[Prototype]]: Object
}
*/
접근자 프로퍼티
프로퍼티 어트리뷰트 | 프로퍼티 디스크립터 객체의 프로퍼티 | 설명 |
---|---|---|
[[Get]] | get | - 데이터 프로퍼티의 값을 읽을 때 호출되는 접근자 함수 - 프로퍼티의 키로 접근하면, [[Get]] 의 값인 getter 함수가 호출되어 프로퍼티의 값을 반환 |
[[Set]] | set | - 데이터 프로퍼티의 값을 저장할 때 호출되는 접근자 함수 - 프로퍼티의 키로 값을 저장하면, [[Set]] 의 값인 setter 함수가 호출되어 프로퍼티의 값을 저장 |
[[Enumerable]] | enumerable | - 프로퍼티 열거 가능 여부를 표현 (불리언) - [[Enumerable]] 값이 false 인 경우, 해당 프로퍼티의 값은 열거할 수 없다 (for .. of / for .. in 사용 불가능) |
[[Configurable]] | configurable | - 프로퍼티의 재정의 가능 여부를 표현 (불리언) - [[Configuratlbe]] 의 값이 false인 경우, 해당 프로퍼티 값 변경 또는 삭제가 금지된다 - [[Configurable]] 이 false여도, [[Value]] 변경과 [[Writable]] 값만 true로 설정할 수 있다 |
const person = {
firstName: 'hoon',
lastName: 'oh',
// 프로퍼티 키 firstName과 lastName의 값을 받기위한 접근자 함수로 이루어진 접근자 함수
// getter 함수
get fullName() {
return `${this.firstName} ${this.lastName}`
},
// 프로퍼티 키 firstName과 lastName의 값에 접근하기 위한 접근자 함수로 이루어진 접근자 함수
// setter 함수
set fullName(name) {
[this.firstName, this.lastName] = name.split(' ')
}
}
// 프로퍼티 키에 접근자 함수를 활용하여 프로퍼티의 값 참조
console.log(person.firstName + " " + person.lastName)
// 접근자 프로퍼티 setter를 활용해 프로퍼티 값에 저장
// setter 함수 호출
person.fullName = "John Cena"
console.log(person)
// 접근자 프로퍼티를 사용하여 프로퍼티 값 참조
// getter 함수 호출
console.log(person.fullName)
// firstName은 객체의 데이터 프로퍼티
// [[Value]] [[Writable]] [[Enumerable]] [[Configurable]]
let descriptor = Object.getOwnPropertyDescriptor(person, 'firstName')
console.log(descriptor);
// fullName은 객체의 접근자 프로퍼티
// [[Get]]] [[Set]] [[Enumerable]] [[Configurable]]
descriptor = Object.getOwnPropertyDescriptor(person, 'fullName')
console.log(descriptor);
접근자 프로퍼티
접근자 프로퍼티로 값에 접근하면
- [[Get]] 메서드 호출
- 프로퍼티 키가 유효한지 확인
- 프로토타입 체인에서 프로퍼티 검색
- 검색된 키의 프로퍼티가 데이터인지 접근자인지 확인
- 접근자 프로퍼티의 getter 함수를 호출하여 결과를 반환
프로퍼티 정의
const person = {};
Object.defineProperty(person, "firstName", {
value: "Hoon",
writable: true,
enumerable: true,
configurable: true,
});
const firstNameDescriptor = Object.getOwnPropertyDescriptor(
person,
"firstName"
);
console.log("firstName: ", firstNameDescriptor);
// firstName: {
// value: 'Hoon',
// writable: true,
// enumerable: true,
// configurable: true
// }
프로퍼티 정의
Object.defineProperty(person, "lastName", {
value: "Oh",
});
const lastNameDescriptor = Object.getOwnPropertyDescriptor(person, "lastName");
console.log("lastName: ", lastNameDescriptor);
/**
lastName: {
value: 'Oh',
writable: false,
enumerable: false,
configurable: false
}
*/
console.log(Object.keys(person));
// [ 'firstName' ]
프로퍼티 정의
Object.defineProperty(person, "fullName", {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(name) {
[this.firstName, this.lastName] = name.split(" ");
},
enumerable: true,
configurable: true,
});
const fullnameDescriptor = Object.getOwnPropertyDescriptor(person, "fullName");
console.log("fullName: ", fullnameDescriptor);
/**
fullName: {
get: [Function: get],
set: [Function: set],
enumerable: true,
configurable: true
}
*/
객체 변경 방지
- 객체 확장 금지
- 객체 밀봉
- 객체 동결
- 불변 객체
객체 확장 금지
const person = {
name: 'Hoon'
}
Object.preventExtensions(person)
console.log(Object.isExtensible(person)); // false
person.age = 31 // 무시
console.log(person) // name: 'hoon'
Object.defineProperty(person, 'age', { value: 31}) // 무시
console.log(person) // name: 'hoon'
객체 밀봉
const person = {
name: "Hoon",
};
Object.seal(person);
console.log(Object.isSealed(person)); // true
person.age = 31; // 무시
console.log(person); // name: 'hoon'
Object.defineProperty(person, "age", { value: 31 }); // 무시
console.log(person); // name: 'hoon'
delete person.name // 무시
console.log(person) // name: 'hoon'
person.name = "Ellie" // 재할당은 가능
console.log(person) // name: 'Ellie'
객체 동결
const person = {
name: "Hoon",
};
Object.freeze(person);
console.log(Object.isFrozen(person)); // true
person.age = 31; // 무시
console.log(person); // name: 'hoon'
Object.defineProperty(person, "age", { value: 31 }); // 무시
console.log(person); // name: 'hoon'
delete person.name; // 무시
console.log(person); // name: 'hoon'
person.name = "Ellie"; // 무시
console.log(person); // name: 'hoon'
불변 객체
function deepFreeze(target) {
// 타겟이 존재하고, 객체형 데이터이며, 동결이 되지 않았을 경우
if (target && typeof target === 'object' && !Object.isFrozen(target)){
// 현재 객체 동결
Object.freeze(target)
// 객체의 키 값으로 순환을 하여 각각의 키에 해당하는 요소 동결
Object.keys(target).forEach(key => deepFreeze(target[key]))
}
return target
}
06. 프로퍼티 어트리뷰트
By hoonnotes
06. 프로퍼티 어트리뷰트
- 64