프로퍼티와 프로퍼티 어트리뷰트
프로퍼티 어트리뷰트
오늘은 프로퍼티 어트리뷰트에 대해서 알아보자. 한국말로 번역하면 속성 속성이다. 하지만 자바스크립트에서 속성은 두가지로 구분하여 사용하여야 한다. 이번 시간에는 속성 중 하나인 프로퍼티에 대해 알아보자
내부슬롯 internal slot
내부슬롯과 내부메서드는 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 프로퍼티와 메서드이다.
내부슬롯은 개발자가 직접 접근할 수는 없다.
하지만, [[Prototype]] 내부슬롯은 proto를 통해 간접적으로 접근할 수 있다.
프로퍼티 어트리뷰트와 프로퍼티 디스크립터 객체
자바스크립트 엔진은 프로퍼티 생성 시 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의한다.
1 | let a = { name: "kim", age: 28 }; |
프로퍼티 어트리뷰트란 내부슬롯이다. 따라서 직접 접근할 순 없지만, Object.getOwnPropertyDescriptor 메서드로 간접적으로 접근할 수 있다.
다만 간접적으로 접근만 가능한 것이므로 위 메서드로 값을 변경하거나 할 수는 없다.
⇒ 프로퍼티 생성될 때 [[value]]는 프로퍼티 값으로 초기화 되고 나머지는 true로 초기화된다.
1 | const person = { |
- 프로퍼티 디스크립터 객체를 반환한다. 존재하지 않거나 상속받은 프로퍼티라면 undefined 반환
데이터 프로퍼티와 접근자 프로퍼티
1. 데이터 프로퍼티
키와 값으로 구성된 일반적인 프로퍼티
- 프로퍼티의 값 [[value]]
- 값의 갱신 가능여부 [[writable]] : false이면 프로퍼티의 [[value]]의 값을 변경할 수 없는 읽기 전용 프로퍼티
- 열거 가능여부 [[enumerable]] : for…in 혹은 Object.keys 메서드로 열거 가능 여부
- 재정의 가능여부 [[configurable]] : false이면 해당 프로퍼티 삭제, 프로퍼티 어트리뷰트 값의 변경 금지
2. 접근자 프로퍼티
자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수로 구성된 프로퍼티
- [[get]] : 접근자 프로퍼티 키로 프로퍼티 값에 접근하면 프로퍼티 어트리뷰트 [[get]]의 값 즉, getter 함수가 호출되고 그 결과가 프로퍼티 값으로 반환된다.
- [[set]] : 접근자 프로퍼티 키로 프로퍼티 값을 저장하면 프로퍼티 어트리뷰트 [[set]]의 값 즉, setter 함수가 호출되고 그 결과가 프로퍼티 값으로 저장된다.
- [[enumerate]]
- [[configurable]]
1 | const person = { |
접근자 프로퍼티와 데이터 프로퍼티 구분 방법
1 | // 일반 객체의 __proto__는 접근자 프로퍼티 |
위 예시는 접근자 프로퍼티의 경우 다음과 같은 프로퍼티 어트리뷰트가 나오고 데이터 프로퍼티의 경우 출력되는 프로퍼티 어트리뷰트가 다른 것을 확인할 수 있다.
프로퍼티 정의
프로퍼티를 정의한다. 라는 것은 새로운 프로퍼티 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나 기존 프로퍼티 어트리뷰트를 재정의하는 것을 말한다.
데이터 프로퍼티 정의
1 | const person = {}; |
- Object.defineProperty 메서드로 프로퍼티 어트리뷰트 정의할 수 있다. 인수로는 객체의 참조, 데이터 프로퍼티의 키(문자열), 프로퍼티 디스크립터 객체를 전달한다.
- 디스크립터 객체 누락시키면 false가 기본값
궁금증
왜 프로퍼티 동적으로 생성해줄 때, 프로퍼티 어트리뷰트 생략하는데 프로퍼티 어트리뷰트값이 true인데, define 메서드를 사용할 때 생략하면 기본값 false?
1 | const obj = {}; |
동적으로 생성시에 편의를 위해서 true로 설정된다. 그렇지 않은 경우 Object.defineProperty() 메서드를 사용할 때, 생략하는 어트리뷰트는 false로 설정된다.
writable : false
1 | // [[writable]] 값이 false 인 경우 해당 프로퍼티의 [[value]]의 값 변경할 수 없다. |
enumerable : false
1 | // [[enumerable]] 값이 false 인 경우 해당 프로퍼티는 for...in 문이나 Object.keys 등으로 열거할 수 없다. |
configurable : false
1 | // [[configurable]] 값이 false 인 경우 해당 프로퍼티를 삭제할 수 없다. |
접근자 프로퍼티 정의
1 | Object.defineProperty(person, "fullName", { |
- lastName은 writable이 false여서 값이 안바뀌는 것을 볼 수 있다.
객체 변경 방지
객체 변경을 방지하는 메서드를 제공한다. 종류에 따라 금지하는 강도가 다르다.
직속 프로퍼티만 방지(얕은 방지)
| 구분 | 메서드 | 프로퍼티 추가 | 삭제 | 값 읽기 | 값 쓰기 | 프로퍼티 어트리뷰트 재정의 |
|---|---|---|---|---|---|---|
| 객체 확장 금지 | Object.preventExtensions | X | O | O | O | O |
| 객체 밀봉 | Object.seal | X | X | O | O | X (configurable : false) |
| 객체 동결 | Object.freeze | X | X | O | X (writable : false) | X (configurable : false) |
객체 확장 금지 확인 메서드 - Object.isExtensible( ) false면 확장 금지된 객체
객체 밀봉 확인 메서드 - Object.isSealed( ) true면 밀봉된 객체
객체 동결 메서드 - Object.isFrozen( ) true면 동결된 객체
깊은 방지를 구현하려면 재귀적으로 객체 값을 갖는 모든 프로퍼티에 대해 Object.freeze 메서드를 호출해야한다.
1 | function deepFreeze(target) { |