Javascript

[모자딥]프로퍼티 어트리뷰트 16.07 ~ 16.08

index.ys 2023. 11. 23. 22:32

프로토타입

  • 어떤 객체의 상위(부모)객체의 역할을 하는 객체
  • 프로토타입은 하위 객체에게 자신의 프로퍼티와 메서드를 상속한다.
  • 프로퍼티와 메서드를 상속받은 하위 객체는 상위 객체의 프로퍼티와 메서드를 자유롭게 사용 가능

예제 16.07

  • 일반객체 : 변수에 {}로 할당된 객체
  • 함수객체 : function () {}의 객체
프로퍼티 어트리뷰트 프로퍼티 디스크립터
객체의 프로퍼티
설명
[[Get]] get 접근자 함수, getter 함수가 호출되고 결과가 프로퍼티값으로 반환됨
[[Set]] set 프로퍼티의 값을 저장할 떄 호출되는 접근자 함수 접근자 프로퍼티 키로 프로퍼티 값을 저장하면 setter 함수가 호출되고 프로퍼티 값으로 저장
[[Enumrable]] enumerable - 열거가능 여부
- false인 경우 Object.keys, for in 메서드로 열거할 수없음
[[Configurable]] configurable - 프로퍼티 재정의 가능여부
- false인 경우 프로퍼티의 삭제 변경이 금지
- [[Writable]]이 true인 경우 [[Value]]의 변경과 [[Writable]]을 false로 변경하는 것은 허용
  • 접근자 프로퍼티와 데이터 프로퍼티를 구별하는 방법
  • 접근자 프로퍼티와 데이터 프로퍼티의 Object.getOwnPropertyDescriptor 메서드가 반환한 값이다름
// 일반 객체의 __proto__는 접근자 프로퍼티다.
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));
// {get: ƒ, set: ƒ, enumerable: false, configurable: true}

// 함수 객체의 prototype은 데이터 프로퍼티다.
console.log(Object.getOwnPropertyDescriptor(function () { }, 'prototype'));
// {value: {...}, writable: true, enumerable: false, configurable: false}

예제 16.08

  • 새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의
  • 기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의 할 수 있다.
  • Object.defineProperty메소드를 사용하여 프로퍼티 어트립트 정의
const person = {};

// 데이터 프로퍼티 정의 => person 객체에 firstName 속성 추가 및 프로퍼티의 어트리뷰트를 정의
// Object.defineProperty 첫번쨰 인자로 객체의 참조, 데이터 프로퍼티의 키 문자열, 프로퍼티 디스크럽터 객체전달
// true나 false로 명시적으로 정의 가능
Object.defineProperty(person, 'firstName', {
    value: 'Ungmo',
    writable: true,
    enumerable: true, //false
    configurable: true //false
});

//person 객체에 'lastName' 프로퍼티키 문자열 지정, 프로퍼티 디스크립터 객체 전달
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(' ');
    },
    //true를 false로 변경하기 가능
    enumerable: true,
    configurable: true
});

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

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