🔑프로퍼티 어트리뷰트를 이해해보자
-WHAT IS❓
내부 슬롯과 내부 메서드는 자바스크립트 엔진의 알고리즘을 설명하기 위해 이크마스크립트 사양에서 사용하는 의사 프로퍼티와 의사 메서드이다.
- 내부 슬롯과 내부 메서드는 자바스크립트 엔진의 내부 로직이므로 원칙적으로 자바스크립트는 내부 슬롯과 메서드에 직접 접근하거나 호출 할 수는 없지만 간접적으로 접근할 수 있는 수단을 제공한다.
-HOW TO USE❕❓
- 모든 객체는 [[prototype]]이라는 내부 슬롯을 가져 proto를 통해 간접적으로 접근할 수 있다.
<script> const o = {}; o.[[Prototype]] // 직접 접근 불가능 o.__proto__ // Object.prototype, 간접적으로 접근할 수 있는 수단 제공 </script>
-WHAT IS❓
- 자바스크립트 엔진은 프로퍼티를 생성할 때
프로퍼티의 상태
를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의한다.프로퍼티 상태
란프로퍼티의 값
,값의 갱신 가능
,열거 가능
,재정의 가능 여부
를 말한다.- 프로퍼티 어트리뷰트는 자바스크립트 엔진이 관리하는 내부 상태 값인 내부 슬롯[[Value]].[[Writable]].[[Enumerable]].[[Configurable]]]이다.
-HOW TO USE❕❓
<script>
const person = {
name: 'jamie'
};
// 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스립터 객체를 반환한다.
console.log(Object.getOwnPropertyDescriptor(person,'name'));
// name: { configurable: true, enumerable: true, value: "jamie", writable: true }
</script>
-WHAT IS❓
- Object.getOwnPropertyDescriptor 메서드는 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체를 반환하고 존재하지 않는 프로퍼티나 상속받은 프로퍼티에 대한 프로퍼티 디스킵터를 요구시 undefined가 반환된다.
- Object.getOwnPropertyDescriptors 메서드는 모든 프로퍼티의 프로퍼티 어트리뷰트를 정보를 제공하는 프로퍼티 객체들을 반환한다.
<script> const person = { name: 'jamie' }; person.age = 26; // 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스립터 객체를 반환한다. console.log(Object.getOwnPropertyDescriptors(person)); /* { name: { configurable: true, enumerable: true, value: "jamie", writable: true } age: { configurable: true, enumerable: true, value: 26, writable: true} */ </script>
-WHAT IS❓
데이터 프로퍼티
란키와 값으로 구성
된 일반적인 프로퍼티이다. 지금까지 살펴본 모든 프로퍼티는 데이터 프로퍼티이다.접근자 프로퍼티
란 자체적으로 값을 갖지않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는접근자 함수로 구성
된 프로퍼티이다.
데이터 프로퍼티
데이터 프로퍼티
는 다음의 표에 나오는 프로퍼티 어트리뷰를 갖고 프로퍼티 어트리뷰트는 자바스크립트 엔진이 프로퍼티를 생성할 때 기본값으로 자동 정의된다.
- Object.getOwnPropertyDescriptors 메서드가 반환한 프로퍼티 디스크립터 객체를 살펴보면 value는 'jamie'로 즉 프로퍼티 어트리뷰트[[value]]의 값이 'jamie'인 것을 의미한다.
- configurable, enumerable, writabled의 프로퍼티의 값 모두 true라는 것 역시 [[configurable]], [[enumerable]], [[writable]]의 값이 모두 모두 true인 것과 같다.
- 프로퍼티가 정적으로 혹은 동적으로 생성될 때 [[value]]의 값은 프로퍼티의 값으로 초기화되며 [[configurable]], [[enumerable]], [[writable]]의 값도 true로 초기화된다.
접근자 프로퍼티
접근자 프로퍼티
는 자체적인 값 갖지않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수로 구성된 프로퍼티로 다음과 같은 프로퍼티 어트리뷰트를 갖는다.
-접근자 함수는 getter/setter 함수라고도 부르고 getter와 setter함수를 모두 정의하거나 하나만 정의할 수 있다.
- configurable, enumerable, writabled의 프로퍼티의 s값 모두 true라는 것 역시 [[configurable]], [[enumerable]], [[writable]]의 값이 모두 모두 true인 것과 같다.
- 프로퍼티가 정적으로 혹은 동적으로 생성될 때 [[value]]의 값은 프로퍼티의 값으로 초기화되며 [[configurable]], [[enumerable]], [[writable]]의 값도 true로 초기화된다
- person 객체의 firstName과 lastName 프로퍼티는 일반적인
데이터 프로퍼티
이다.- 메서드 앞에 get, set이 붙은 메서드가 있는데 이것들이 바로 getter와 setter 함수이며 getter/setter 함수의 이름 fullName이
접근자 프로퍼티
이다.접근자 프로퍼티
는 자체적으로 값(프로퍼티 어트리뷰트[[value]])을 가지지 않고 단지 데이터 프로퍼티의 값을 읽거나 저장할 때 관여할 뿐이다.<script> const person = { // 데이터 프로퍼티 firstName: 'MinJae', lastName: 'Kim', // fullName은 접근자 함수로 구성된 접근자 프로퍼티 // getter 함수 get fullName(){ return `${this.firstName} ${this.lastName}`; }, // setter 함수 set fullName(name) { [this.firstName, this.lastName] = name.split(' '); } }; // 데이터 프로퍼티를 통한 프로퍼티 값의 참조 console.log(person.firstName + ' ' + person.lastName); // "MinJae Kim" // 접근자 프로퍼티를 통한 프로퍼티 값의 저장 // 접근자 프로퍼티 fullName에 값을 저장하면 setter 함수 호출 person.fullName = 'Jamie kim'; console.log(person) // { fristName: "Jamie", fullName: "Jamie kim", lastName: "Kim" } // 접근자 프로퍼티를 통한 프로퍼티 값의 참조 // 접근자 프로퍼티 fullName에 접근하면 getter 함수 참조 console.log(person.fullName); // "Jamie kim" // firstName은 데이터 프로퍼티 // 데이터 프로퍼티는 [[value]], [[configurable]], [[enumerable]], [[writable]] // 프로퍼티 어트리뷰를 갖는다. let descriptor = Object.getOwnPropertyDescriptor(person, 'firstName') console.log(descriptor) // { configurable: true, enumerable: true, value: "Jamie", writable: true } // fullName은 접근자 프로퍼티 // 접근자 프로퍼티는 [[get]], [[set]], [[configurable]], [[enumerable]] // 프로퍼티 어트리뷰트를 갖는다. descriptor = Object.getOwnPropertyDescriptor(person, 'fullName') console.log(descriptor)// { get : f, set : f, configurable: true, enumerable: true } </script>
- 내부 슬롯/메서드 관점에서 설명하면
접근자 프로퍼티
fullName으로 프로퍼티 값에 접근하면 내부적으로 [[Get]] 내부 메서드가 호출되어 다음과 같이 동작한다.
- 프로퍼티 키가 유효한지 (키는 문자열 또는 심벌) 확인한 후 'fullName' 문자열이므로 유효한 프로퍼티 키이다.
- 프로토타입 체인에서 프로퍼티를 검색해 person 객체에 fullNme 프로퍼티가 존재함을 확인한다.
- 검색된 fullName 프로퍼티가 데이터 프로퍼티인지 접근자 프로퍼티인지 확인 결과 fullNme 프로퍼티는 접근자 프로퍼티이다.
- 접근자 프로퍼티 fullNme의 프로퍼티 어트리뷰ㅡ[[Get]]의 값, getter 함수를 호출하여 결과를 반화한다. 이 값은 Object.getOwnPropertyDescriptor 메서드가 반환하는 프로퍼티 디스크립터 객체의 get 프로퍼티의 값과 같다.
-꼭 알아야하는 개념 프로토 타입
- 프로토타입은 어떤 객체의 상위 (부모) 객체의 역할을 하는 객체이다.
프로토타입은 하위 객체에게 자신의 프로퍼티와 메서드를 상속하는데 이를 상속을 받은 하위 객체는 자신의 프로퍼티 또는 메서드인 것처럼 사용할 수 있다.- 프로토타입 체인은 프로토타입이 단방향 링크드 리스트 형태로 연결되더 있는 상속 구조를 말한다. 객체의 프로퍼티나 메서드에 접근하려할 때 해당 객체에 접근하려는 프로퍼티 또는 메서드가 없다며 프로토타입 체인을 따라 프로토타입의 프로퍼티나 메서드를 검색한다.
따라서 접근자 프로퍼티와 데이터 프로퍼티를 구별하는 방법은
## - 프로퍼티 정의
-**WHAT IS❓**
- **프로퍼티 정의**란 **새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나, 기존 프로퍼티의 어트리뷰트를 재정의**하는 것을 말한다.
> 프로퍼티 값을 갱신 가능하도록 할건지. 열거 가능하도록 할건지, 재정의 가능하도록 할건지를 정의할 수 있고 이를 통해 객체의 프로퍼티가 어떻게 동작하는지 명확하게 정의할 수 있다.
-**HOW TO USE❕❓**
- **Object.defindProperty 메서드**를 사용하면 **프로퍼티의 어트리뷰트를 정의**할 수 있다.
- 인수로 객체의 참조와 프로퍼티 키의 문자열, 프로퍼티 디스크립터 객체를 전달한다.
>- **Object.defindProperty 메서드**로 프로퍼티를 정의 할때 프로퍼티 디스크립터 객체의 프로퍼티 일부 생략 할 수 있고 프로퍼티 디스크립터 객체에서 생략된 기본값은 다음과 같다.

- **Object.defindProperties 메서드**는 **여러개의 프로퍼티를 한 번에 정의**할 수 있다.
## - 객체 변경 방지
-**WHAT IS❓**
- **객체**는 **변경가능한 값**이므로 재할 당 없이 직접 변경할 수 있다.
- **프로퍼티를 추가, 삭제, 프로퍼티 값 갱신**할 수 있으며 Object.defineProperties 메서드를 사용하여 **프로퍼티 어트리뷰트를 재정의**할 수 도 있다.
> -자바스크립트는 **객체의 변경을 방지하는 다양한 메서드를 제공**한다.
- 객체 변경 방지 메서드들은 객체의 변경을 금지하는 강도가 다르다.

-**HOW TO USE❕❓**
### - 객체 확장 금지
>- **WHAT IS❓** **Object.preventExtensions 메서드**는 **객체의 확장을 금지**한다.
- **객체 확장 금지**란 **프로퍼티 추가 금지**를 의미하여 **확장이 금지된 객체는 프로퍼티 추가가 금지된다.**
>-**HOW TO USE❕❓**
- 프로퍼티는 **프로퍼티 동적 추가**와**Object.defineProperties 메서드로 추가할 수 있는데 이 두가지 추가 방법이 금지된다.
- **확장 가능 객체 여부**는 **Object.isExtensible 메서드로 확인** 가능하다
### - 객체 밀봉
>- **WHAT IS❓** **Object.seal 메서드**는 **객체를 밀봉하여 프로퍼티 추가 및 삭제와 프로퍼티 어트리뷰트 재정의 금지**한다
- 즉 **밀본된 객체는 읽기와 쓰기만 가능하다.**
>-**HOW TO USE❕❓**
- **밀봉 객체 여부**는 **Object.isSealed 메서드로 확인** 가능하다
### - 객체 동결
>- **WHAT IS❓** **Object.freeze 메서드**는 **객체를 동결하여 프로퍼티 추가 및 삭제와 프로퍼티 어트리뷰트 재정의 금지, 프로퍼티 값 갱신 금지**한다
- 즉 **동결된 객체는 읽기와 가능하다.**
>-**HOW TO USE❕❓**
- **밀봉 객체 여부**는 **Object.isFrozen 메서드로 확인** 가능하다
### - 불변 객체
- 지금까지의 변경 방지 메서드들은 **얕은 변경 방지**로 **직속 프로퍼티만 변경이 방지되고 중첩 객체까지는 영향을 주지 못해** Object.freeze 메서드로 객체를 동결해도 중첩 객체까지는 동결할 수 없다.
>- **WHAT IS❓** **객체의 중첩 객체까지 동결하여 변경이 불가능한 읽기 전용**의 **불변객체**를 구현해야한다.
>-**HOW TO USE❕❓**
- **불변객체**를 만들기 위해 **객체를 값으로 갖는 모든 프로퍼티에 대해 재귀적으로 Object.freeze 메서드를 호출**해야한다.