[모자딥] 16장 프로퍼티 어트리뷰트

Minha Ahn·2024년 11월 6일
0
post-thumbnail

🔩 내부 슬롯과 내부 메서드

ECMAScript 사양에서 자바스크립트 엔진의 내부 동작을 설명하기 위해 사용하는 개념으로,
개발자가 직접 접근하거나 호출하는 건 아니고 자바스크립트 엔진이 내부적으로만 사용하는 속성과 메서드입니다.

1. 내부 슬롯

🔎 내부 슬롯이란?

자바스크립트 엔진이 각 객체의 상태를 관리하기 위해 사용하는 숨겨진 속성

  • 개발자가 직접 접근하거나 수정 불가
  • 일부 내부 슬롯에 대해 간적적으로 접근할 수 있는 방법 제공
    • 예시) [[Prototype]]Object.getPrototypeof() 메서드 / __proto__ 프로퍼티 제공

2. 내부 메서드

🔎 내부 메서드란?

특정 동작을 수행하기 위해 엔진 내부에서 호출되는 함수

  • 개발자가 JS 코드에서 직접 호출 불가, 그러나 함수 호출이나 객체 생성 등의 과정에서 자동으로 사용
    • 예시) new 연산자와 함께 생성자 함수 호출 ⇒ 내부 메서드 [[Constructor]] 실행
  • 일부 내부 메서드에 대해 간접적으로 접근할 수 있는 방법 제공
    • 예시) Function.prototype.call() / Function.prototype.apply() ⇒ 내부에서 [[Call]] 메서드 호출



🧬 프로퍼티

1. 프로퍼티(속성) 어트리뷰트

🔎 프로퍼티 어트리뷰트란?

객체의 프로퍼티에 대한 상태

🔎 프로퍼티 디스크립터 객체란?

프로퍼티 어트리뷰트 정보를 객체로 표현한 것

  • 일반적인 객체의 프로퍼티 어트리뷰트의 구성
    • value / writable / enumerable / configurable
  • Object.getOwnPropertyDescriptor(객체명, 속성명 문자열) : 프로퍼티 어트리뷰트 확인
    • 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체 반환
    • 존재하지 않는 프로퍼티 or 상속받은 프로퍼티는 undefined 반환
      • 상속받은 프로퍼티는 왜 undefined가 반환되는걸까?
        • Object.getOwnPropertyDescriptor() 메서드는 객체 자신이 직접 소유하고 있는 프로퍼티만을 대상으로 하기 때문에 상속받는 프로퍼티에 대해서는 정보를 제공하지 않습니다.
        • 참고로, 상속받는 프로퍼티는 자식 객체가 실제로 물려받는 것이 아닌 프로토타입 체인으로 상속받는 것입니다.
  • Object.getOwnPropertyDescriptors(객체명) : 여러 프로퍼티 어트리뷰트 한번에 확인

2. 프로퍼티의 종류 (1) - 데이터 프로퍼티

🔎 데이터 프로퍼티란?

키와 값으로 구성된 일반적인 프로퍼티

  • 객체에 직접 할당하는 경우, 자바스크립트 엔진이 프로퍼티 생성할 때 기본값으로 자동 정의
  • 데이터 프로퍼티가 갖고 있는 프로퍼티 어트리뷰트
    • [[Value]] : 프로퍼티의 값
    • [[Writable]] : 값의 갱신 가능 여부
    • [[Enumerable]] : 열거 가능 여부
    • [[Configurable]] : 재정의 가능 여부
const person = {
  name: '철수'
};
person.age = 20
console.log(Object.getOwnPropertyDescriptors(person));
{
  name: { value: '철수', writable: true, enumerable: true, configurable: true },
  age: { value: 20, writable: true, enumerable: true, configurable: true }
}

3. 프로퍼티의 종류 (2) - 접근자 프로퍼티

🔎 접근자 프로퍼티란?

다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수로 구성된 프로퍼티

  • 자체적으로 값을 가지지 않으나, 데이터 프로퍼티의 값을 읽거나 저장할 때 관여
    • get 이나 set 키워드가 붙은 함수 ⇒ 각각 getter 함수, setter 함수
  • 객체에 직접 할당하는 경우, 자바스크립트 엔진이 프로퍼티 생성할 때 기본값으로 자동 정의
  • 접근자 프로퍼티가 갖고 있는 프로퍼티 어트리뷰트
    • [[Get]] : 값을 읽을 때 호출되는 접근자 함수 (getter 함수)
    • [[Set]] : 값을 저장할 때 호출되는 접근자 함수 (setter 함수)
    • [[Enumerable]] : 위와 동일
    • [[Configurable]] : 위와 동일
  • 하나의 프로퍼티에 [[Get]] , [[Set]] 을 함께 정의 ⇒ 동일한 이름의 getter와 setter는 하나의 프로퍼티
const person = {
  firstName: 'Ungmo',
  lastName: 'Lee',
  get fullName() {
    return `${this.firstName} ${this.lastName}`
  },
  set fullName(name) {
    [this.firstName, this.lastName] = name.split(" ");
  }
}

console.log(Object.getOwnPropertyDescriptor(person, 'fullName'));
{
  get: [Function: get fullName],
  set: [Function: set fullName],
  enumerable: true,
  configurable: true
}
  • 접근자 프로퍼티 동작 과정
person.personInfo = 'Heegun Lee';  // setter 호출
console.log(person.fullName);  // getter 호출
  1. 프로퍼티 유효여부 확인 (문자열 or 심벌)
  2. 프로토타입 체인에서 프로퍼티 검색
  3. 데이터 or 접근자 프로퍼티인지 확인
  4. 내부 슬롯 프로퍼티에 저장된 함수 호출 & 반환

궁금!

  • 호출된 프로퍼티가 getter인지 setter인지 어떻게 구분하지?
    • 자바스크립트 엔진이 자동으로 구분합니다. (간단ㅎ)
  • get이나 set이 붙지 않는 함수는 데이터 프로퍼티? 접근자 프로퍼티?
    • get과 set이 붙지 않는다면 데이터 프로퍼티입니다~
    • 함수는 일급 객체이기 때문에 값으로 할당이 가능하죠!

4. 데이터 프로퍼티, 접근자 프로퍼티 구분 방법

  • Object.getOwnPropertyDescriptor 가 반환하는 프로퍼티 디스크립터 객체로 구분 가능
  • 데이터 프로퍼티 ⇒ value, writable, enumerable, configurable로 구성
const obj = { key: 'value' };
console.log(Object.getOwnPropertyDescriptor(obj, 'key'));
// { value: 'value', writable: true, enumerable: true, configurable: true }
  • 접근자 프로퍼티 ⇒ get, set, enumerable, configurable로 구성
const obj = {
  get key() {
    return 'value';},
  set key(value) {
    console.log('setter called');
  }
};
console.log(Object.getOwnPropertyDescriptor(obj, 'key'));
// { get: [Function: get key], set: [Function: set key], enumerable: true, configurable: true }

5. 프로퍼티 정의

🔎 프로퍼티 정의란?

새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나, 기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의하는 것

  • Object.defineProperty(객체명, 속성명 문자열, 프로퍼티 디스크립터 객체) : 프로퍼티 어트리뷰트 정의
  • 데이터 프로퍼티든, 접속자 프로퍼티든 일부만 정의 가능
    • 단, 미작성한 어트리뷰트는 undefined 혹은 false로 설정
const person = {};

Object.defineProperty(person, 'firstName', {
  value: 'Ungmo',writ
  enumerable: true,
  configurable: true
});

Object.defineProperty(person, 'lastName', {
  value: 'Lee'
});
Object.defineProperty(person, 'fullName', {
  get() {
    return `${this.firstName} ${this.lastName}`
  },
  set(name) {
    [this.firstName, this.lastName] = name.split(' ');
  },
  enumerable: true,
  configurable: true
});
  • Object.defineProperties(객체명, 프로퍼티 디스크립터 객체) : 여러 프로퍼티 어트리뷰트 한번에 정의
const person = {};
Object.definedProperties(person, {
  데이터 프로퍼티 이름: { ... },
  데이터 프로퍼티 이름: { ... },
  접근자 프로퍼티 이름: { ... },
});



🚫 객체 변경 방지

  • 객체는 변경 가능한 값이므로 재할당없이도 직접 변경 가능
    • 프로퍼티 추가 / 삭제 / 갱신 가능
    • Object.defineProperty 혹은 Object.defineProperties 메서드로 프로퍼티 어트리뷰트 재정의 가능
  • 객체 변경을 방지하려면 어떻게 해야할까? ⇒ 메서드가 있다!
구분메서드속성 추가속성 삭제속성 값 읽기속성 값 쓰기 (갱신)어트리뷰트 재정의
객체 확장 금지Object.preventExtensionsXOOOO
객체 밀봉Object.sealXXOOX
객체 동결Object.freezeXXOXX
  • 하지 말라는 거 하라고 하면 strict mode에서는 모두 에러 발생
    strict mode가 아니면 defineProperty만 에러 발생

1. 객체 확장 금지 | Object.preventExtensions

  • 객체 확장 금지 === 프로퍼티 추가 금지

    • 프로퍼티 추가 메서드 사용 불가 (프로퍼티 동적 추가, Object.defineProperty 메서드로 추가)
  • 관련 메서드

    • Object.preventExtensions(객체) : 확장 금지 선언
    • Object.isExtensible(객체명) : 확장 가능 여부 확인

2. 객체 밀봉 | Object.seal

  • 객체 밀봉 === 프로퍼티 추가, 삭제, 어트리뷰트 재정의 금지
    • 프로퍼티 추가 메서드 사용 불가 (프로퍼티 동적 추가, Object.defineProperty)
    • 속성 삭제 메서드 사용 불가 (delete)
    • 어트리뷰트 재정의 메서드 사용 불가 (Object.defineProperty로 value만 변경 가능)
  • 관련 메서드
    • Object.seal(객체) : 밀봉 선언
    • Object.isSealed(객체명) : 밀봉 여부 확인
  • 프로퍼티 어트리뷰트에서 configurable이 false인 상태

3. 객체 동결 | Object.freeze

  • 객체 동결 === 프로퍼티 추가, 삭제, 프로퍼티 어트리뷰트 재정의 금지, 프로퍼티 값 갱신 금지
    • 싹 다 안됨
    • 읽기만 가능
  • 관련 메서드
    • Object.freeze(객체) : 동결 선언
    • Object.isFronzen(객체명) : 동결 여부 확인
  • 프로퍼티 어트리뷰트에서 writable, configurable이 false인 상태

4. 불변 객체

  • 위의 메서드들은 직속 프로퍼티 변경만 방지 가능
  • 중첩 객체(정확히는 참조형 데이터)까지 변경 금지를 시켜줄 수 없음
  • 해결 방법 ⇒ 객체를 값으로 갖는 모든 프로퍼티에 대해 재귀적으로 Object.freeze 메서드 호출



✏️ 용어 정리

  • 내부 슬롯과 내부 메서드
    • 내부 슬롯 : 자바스크립트 엔진이 각 객체의 상태를 관리하기 위해 사용하는 숨겨진 속성
    • 내부 메서드 : 특정 동작을 수행하기 위해 엔진 내부에서 호출되는 함수
  • 프로퍼티
    • 프로퍼티 어트리뷰트 : 객체의 프로퍼티에 대한 상태 (4가지 정보)
    • 프로퍼티 디스크립터 : 프로퍼티 어트리뷰트 정보를 제공하는 객체
    • 데이터 프로퍼티 : 키와 값으로 구성된 일반적인 프로퍼티
    • 접근자 프로퍼티 : 접근자 함수로 구성된 프로퍼티
      • 접근자 함수 : 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 함수
    • 프로퍼티 정의 : definedProperty 함수를 이용해 객체의 프로퍼티 어트리뷰트를 명시적으로 정의 혹은 재정의하는 것
  • 객체 변경 방지
    • 객체 확장 금지 : 프로퍼티 추가 금지
    • 객체 밀봉 : (객체 확장 금지) + 프로퍼티 삭제, 어트리뷰트 재정의 금지
    • 객체 동결 : (객체 밀봉) + 프로퍼티 값 갱신 금지
profile
프론트엔드를 공부하고 있는 학생입니다🐌

0개의 댓글