16 - 프로퍼티 어트리뷰트

2022. 9. 6.·🎨 프론트엔드 공부/JS & TS

모던 자바스크립트 Deep Dive 정리

자바스크립트 엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의

데이터 프로퍼티

▶ 프로퍼티를 생성할 때 자동 정의되는 요소들

 

  프로퍼티 어트리뷰트 프로퍼티 디스크립터 객체의 프로퍼티 설명
데이터 프로퍼티 [[Value]] value - 프로퍼티 밸류값
[[Writable]] writable - 프로퍼티 밸류값 변경 가능여부
- false 이면 읽기 전용
[[Enumerable]] enumerable - 열거 가능 여부
- false 이면 for .. in 또는 Object.keys() 메서드로 열거 불가
[[Configurable]] configurable - 재정의 가능 여부
- false 이면 프로퍼티 삭제, 프로퍼티 어트리뷰트 변경 금지
- Writable이 true일 때는 프로퍼티 밸류값과 Writable 어트리뷰트 변경 가능

 

▷ 예시

 

const person = {
  name: 'Lee'
};

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

// 프로퍼티 동적 생성
person.age = 20;

// 모든 프로퍼티의 프로퍼티 어트리뷰트 정보도 확인 가능
console.log(Object.getOwnPropertyDescriptors(person));
/*
{
  name: {value: "Lee", writable: true, enumerable: true, configurable: true},
  age: {value: 20, writable: true, enumerable: true, configurable: true}
}
*/

 

접근자 프로퍼티

▶ 데이터 프로퍼티 값을 읽거나 저장할 때 호출하는 접근자 함수로 구성됨

 

  프로퍼티 어트리뷰트 프로퍼티 디스크립터 객체의 프로퍼티 설명
접근자 프로퍼티 [[Get]] get - 데이터 프로퍼티의 값을 읽는 getter 함수
[[Set]] set - 데이터 프로퍼티의 값을 저장하는 setter 함수
[[Enumerable]] enumerable 데이터 프로퍼티와 동일
[[Configurable]] configurable 데이터 프로퍼티와 동일

 

▷ 예시

 

const person = {
  firstName: 'Harry',
  lastName: 'Kane',

  // 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); // Harry Kane

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

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

// firstName은 데이터 프로퍼티다.
// 데이터 프로퍼티는 [[Value]], [[Writable]], [[Enumerable]], [[Configurable]] 프로퍼티 어트리뷰트를 갖는다.
let descriptor = Object.getOwnPropertyDescriptor(person, 'firstName');
console.log(descriptor);
// {value: "Heung-Min", 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}

 

프로퍼티 정의

▶ 새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나

▶ 기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의할 수 있다

▶ Object.defineProperty() 메서드를 이용

 

const person = {};

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

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

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

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

// [[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: "Son", 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 = 'Harry Kane';
console.log(person); // {firstName: "Harry", lastName: "Kane"}

 

프로퍼티 정의 시 인수를 전달하지 않으면?

 

// defineProperty는 1개의 프로퍼티 어트리뷰트만 정의
Object.defineProperty(person, 'lastName', {
  value: 'Lee' // value만 전달
});

// defineProperties는 여러개의 프로퍼티 어트리뷰트 한 번에 정의
const person = {};

Object.defineProperties(person, {
  // 데이터 프로퍼티 정의
  firstName: {
    value: 'Heung-Min',
    writable: true,
    enumerable: true,
    configurable: true
  },
  lastName: {
    value: 'Son',
    writable: true,
    enumerable: true,
    configurable: true
  },
  // 접근자 프로퍼티 정의
  fullName: {
    // getter 함수
    get() {
      return `${this.firstName} ${this.lastName}`;
    },
    // setter 함수
    set(name) {
      [this.firstName, this.lastName] = name.split(' ');
    },
    enumerable: true,
    configurable: true
  }
});

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

 

 

undefined, false가 기본값으로 정의된다

 

프로퍼티 디스크립터 객체의 프로퍼티 대응하는 프로퍼티 어트리뷰트 생략했을 때의 기본값
value [[Value]] undefined
get [[Get]] undefined
set [[Set]] undefined
writable [[Writable]] false
enumerable [[Enumerable]] false
configurable [[Configurable]] false

 

객체 변경 방지

▶ 객체의 변경을 방지하는 다양한 메서드가 있고, 그마다 금지 강도가 다르다

▷ 아래로 갈수록 강하게 금지

 

구분 메서드 프로퍼티 추가 프로퍼티 삭제 프로퍼티 값 읽기 프로퍼티 값 쓰기 프로퍼티 어트리뷰트 재정의
객체 확장 금지 - 설정:
Object.
preventExtensions(객체명)

- 확인:
Object.isExtensible(객체명) 
X O O O O
객체 밀봉 - 설정:
Object.seal(객체명)

- 확인:
Object.isSealed(객체명)
X X O O X
객체 동결 - 설정:
Object.freeze(객체명)

- 확인:
Object.isFrozen(객체명)
X X O X X

 

▶ 프로퍼티 추가 2가지 방법(동적 추가, defineProperty 계열 메서드)이 있는데 모두 금지

▶ 중첩 객체에는 영향 X (중첩 객체까지 변경 방지하려면 재귀 함수 사용)

'🎨 프론트엔드 공부/JS & TS' 카테고리의 다른 글
  • 18 - 함수와 일급 객체
  • 17 - 생성자 함수에 의한 객체 생성
  • 15 - let, const 키워드와 블록 레벨 스코프
  • 14 - 전역 변수의 문제점
지식물원
지식물원
지식이 자라는 식물원!
  • 지식물원
    지식물원
    지식물원
  • 전체
    오늘
    어제
    • 분류 전체보기 (516) N
      • 🎨 프론트엔드 공부 (253) N
        • JS & TS (92) N
        • HTML & CSS (22)
        • React & Next (49)
        • Vue & Nuxt (22)
        • 기타 (68)
      • 🤓 기술 학습 & 공부 기록 (116)
        • Node.js (0)
        • Python (37)
        • 백엔드 (0)
        • 딥러닝 (1)
        • 컴퓨터 일반 (72)
        • 개발 인프라 (6)
      • 👨‍💻 프로젝트 경험 (6)
        • Work (0)
        • Toy (6)
      • ⚙️ 개발 팁 & 노하우 (21)
        • 프론트엔드 (6)
        • 기타 (15)
      • ☕️ 커리어 & 인터뷰 준비 (88)
        • 코딩 테스트 (88)
      • 📰 기술 트렌드 & 생각 정리 (4)
      • 📚 기타 (25)
        • 마케팅 (15)
        • 비개발서적 (10)
  • 블로그 메뉴

    • 태그
  • 링크

  • 공지사항

    • 모바일 접속 시 코드 하이라이팅 깨질 때
  • 인기 글

  • hELLO· Designed By정상우.v4.10.3
지식물원
16 - 프로퍼티 어트리뷰트
상단으로

티스토리툴바