16장. 프로퍼티 어트리뷰트

Happhee·2021년 12월 6일
0

JS : Depp Dive

목록 보기
13/35
post-thumbnail

1. 내부 슬롯과 내부 메서드

  • 내부 슬롯, 내부 메서드 ([[...]])
    완전한 내부 로직이므로 간접적으로 접근해야함

ex) [[Prototype]])이라는 내부 슬롯 -> _ _ proto _ _로 간접 접근

2. 프로퍼티 어트리뷰트와 프로퍼티 디스크립터 객체

프로퍼티를 생성할 때, 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의

  • 프로퍼티의 상태
    값, 갱신/열거/재정의 가능 여부

  • 프로퍼티 어트리뷰트
    내부 상태 값, Value, Writable, Enumerable, Configurable (false이면 값이 안바뀜)
    Object.getOwnPropertyDescriptor 메서드를 사용해 간접적으로 확인

const person = {
  name: 'Lee'
};

// 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체를 반환한다.
console.log(Object.getOwnPropertyDescriptor(person, 'name'));
// {value: "Lee", writable: true, enumerable: true, configurable: true}

3. 데이터 프로퍼티와 접근자 프로퍼티

  • 데이터 프로퍼티
    키와 값으로 구성
    ex) value, writable, enumrable
const person = {
 name: 'Lee'
};

// 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체를 취득한다.
console.log(Object.getOwnPropertyDescriptor(person, 'name'));
// {value: "Lee", writable: true, enumerable: true, configurable: true}
  • 접근자 프로퍼티
    자체적인 값이 없고, 접근자 함수로 구성된 프로퍼티
    ex) get, set
const person = {
  // 데이터 프로퍼티
  firstName: 'Ungmo',
  lastName: 'Lee',

  // fullName은 접근자 함수로 구성된 접근자 프로퍼티다.
  // getter 함수
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  },
  // setter 함수
  set fullName(name) {
    // 배열 디스트럭처링 할당: "31.1 배열 디스트럭처링 할당" 참고
    [this.firstName, this.lastName] = name.split(' ');
  }
};

// 데이터 프로퍼티를 통한 프로퍼티 값의 참조.
console.log(person.firstName + ' ' + person.lastName); // Ungmo Lee

// 접근자 프로퍼티를 통한 프로퍼티 값의 저장
// 접근자 프로퍼티 fullName에 값을 저장하면 setter 함수가 호출된다.
person.fullName = 'Heegun Lee';
console.log(person); // {firstName: "Heegun", lastName: "Lee"}

// 접근자 프로퍼티를 통한 프로퍼티 값의 참조
// 접근자 프로퍼티 fullName에 접근하면 getter 함수가 호출된다.
console.log(person.fullName); // Heegun Lee

// firstName은 데이터 프로퍼티다.
// 데이터 프로퍼티는 [[Value]], [[Writable]], [[Enumerable]], [[Configurable]] 프로퍼티 어트리뷰트를 갖는다.
let descriptor = Object.getOwnPropertyDescriptor(person, 'firstName');
console.log(descriptor);
// {value: "Heegun", writable: true, enumerable: true, configurable: true}

// fullName은 접근자 프로퍼티다.
// 접근자 프로퍼티는 [[Get]], [[Set]], [[Enumerable]], [[Configurable]] 프로퍼티 어트리뷰트를 갖는다.
descriptor = Object.getOwnPropertyDescriptor(person, 'fullName');
console.log(descriptor);
// {get: ƒ, set: ƒ, enumerable: true, configurable: true}

4. 프로퍼티 정의

Object.defindProperty 메서드를 사용하여 프로퍼티의 어트리뷰트를 정의
한번에 하나의 프로퍼티만 정의 가능!

const person = {};

// 데이터 프로퍼티 정의
Object.defineProperty(person, 'firstName', {
 value: 'Ungmo',
 writable: true,
 enumerable: true,
 configurable: true
});

Object.defineProperty(person, 'lastName', {
 value: 'Lee'
});

let descriptor = Object.getOwnPropertyDescriptor(person, 'firstName');
console.log('firstName', descriptor);
// firstName {value: "Ungmo", writable: true, enumerable: true, configurable: true}

// 디스크립터 객체의 프로퍼티를 누락시키면 undefined, false가 기본값이다.
descriptor = Object.getOwnPropertyDescriptor(person, 'lastName');
console.log('lastName', descriptor);
// lastName {value: "Lee", writable: false, enumerable: false, configurable: false}

// [[Enumerable]]의 값이 false인 경우
// 해당 프로퍼티는 for...in 문이나 Object.keys 등으로 열거할 수 없다.
// lastName 프로퍼티는 [[Enumerable]]의 값이 false이므로 열거되지 않는다.
console.log(Object.keys(person)); // ["firstName"]

// [[Writable]]의 값이 false인 경우 해당 프로퍼티의 [[Value]]의 값을 변경할 수 없다.
// lastName 프로퍼티는 [[Writable]]의 값이 false이므로 값을 변경할 수 없다.
// 이때 값을 변경하면 에러는 발생하지 않고 무시된다.
person.lastName = 'Kim';

// [[Configurable]]의 값이 false인 경우 해당 프로퍼티를 삭제할 수 없다.
// lastName 프로퍼티는 [[Configurable]]의 값이 false이므로 삭제할 수 없다.
// 이때 프로퍼티를 삭제하면 에러는 발생하지 않고 무시된다.
delete person.lastName;

// [[Configurable]]의 값이 false인 경우 해당 프로퍼티를 재정의할 수 없다.
// Object.defineProperty(person, 'lastName', { enumerable: true });
// Uncaught TypeError: Cannot redefine property: lastName

descriptor = Object.getOwnPropertyDescriptor(person, 'lastName');
console.log('lastName', descriptor);
// lastName {value: "Lee", writable: false, enumerable: false, configurable: false}

// 접근자 프로퍼티 정의
Object.defineProperty(person, 'fullName', {
 // getter 함수
 get() {
   return `${this.firstName} ${this.lastName}`;
 },
 // setter 함수
 set(name) {
   [this.firstName, this.lastName] = name.split(' ');
 },
 enumerable: true,
 configurable: true
});

descriptor = Object.getOwnPropertyDescriptor(person, 'fullName');
console.log('fullName', descriptor);
// fullName {get: ƒ, set: ƒ, enumerable: true, configurable: true}

person.fullName = 'Heegun Lee';
console.log(person); // {firstName: "Heegun", lastName: "Lee"}

5. 객체 변경 방지

  • 객체 확장 금지 : Object.preventExtensions
  • 객체 밀봉 : Object.seal , Object.isSealed 메서드로 확인
  • 객체 동결 :추가, 삭제, 재정의, 갱신 금지 -> 읽기만 가능!
    Object.freeze, Object.isFrozen
  • 불변 객체 : 모든 프로퍼티를 순회하면서 재귀적으로 동결해야함
profile
즐기면서 정확하게 나아가는 웹프론트엔드 개발자 https://happhee-dev.tistory.com/ 로 이전하였습니다

0개의 댓글