-
[Javascript] 프로퍼티 어트리뷰트, getOwnPropertyDescriptor,defineProperty,getDeepFrozen웹/JavaScript 2023. 1. 13. 09:07
I. 프로퍼티 어트리뷰트 property attributes
객체의 프로퍼티가 생성될 때 엔진에 의해 자동 정의되는 상태
💡 프로퍼티에는 두 종류가 있음
const person = {// ⭐️ 1. 데이터 프로퍼티들fullName: '홍길동',ageInNumber: 25,// ⭐️ 2. 접근자 프로퍼티들get name () {return this.fullName.split('').map((letter, idx) => idx === 0 ? letter : '*').join('');},get age () { return this.ageInNumber + '세'; },set age (age) {this.ageInNumber = Number(age);}}console.log(person.name, person.age);1. 데이터 프로퍼티의 어트리뷰트
프로퍼티 어트리뷰트설명설정중 생략시 기본값
[[Value]] 프로퍼티의 값 undefined [[Writable]] 값 갱신 가능 여부 - false일 경우 읽기 전용 false [[Enumerable]] 열거(for ... in문, Object.keys 사용) 가능 여부 false [[Configurable]] 프로퍼티의 제거, (value와 writable 제외) 어트리뷰트 수정 가능 여부 false 2. 접근자 프로퍼티의 어트리뷰트
프로퍼티 어트리뷰트설명설정중 생략시 기본값
[[Get]] 객체로부터 값을 읽을 때 호출되는 getter 함수 undefined [[Set]] 객체에 값을 저장할 때 호출되는 setter 함수 undefined [[Enumerable]] 열거(for ... in문, Object.keys 사용) 가능 여부 false [[Configurable]] 프로퍼티의 제거, (value와 writable 제외) 어트리뷰트 수정 가능 여부 false
II. Object의 프로퍼티 어트리뷰트 관련 정적 메서드들
1. getOwnPropertyDescriptor, getOwnPropertyDescriptors
- 객체 프로퍼티 어트피뷰트들의 설명자 descriptor를 반환
const person = {// ⭐️ 1. 데이터 프로퍼티들fullName: '홍길동',ageInNumber: 25,// ⭐️ 2. 접근자 프로퍼티들get name () {return this.fullName.split('').map((letter, idx) => idx === 0 ? letter : '*').join('');},get age () { return this.ageInNumber + '세'; },set age (age) {this.ageInNumber = Number(age);}}// 특정 프로퍼티를 지정하여 반환console.log('1.',Object.getOwnPropertyDescriptor(person, 'fullName'));console.log('2.',Object.getOwnPropertyDescriptor(person, 'ageInNumber'));console.log('3.', // set: undefinedObject.getOwnPropertyDescriptor(person, 'name'));console.log('4.', // get, set 모두 있음Object.getOwnPropertyDescriptor(person, 'age'));// 모든 프로퍼티의 어트리뷰트 객체로 묶어 반환console.log(Object.getOwnPropertyDescriptors(person));2. defineProperty, defineProperties
- 객체의 프로퍼티를 정의
const person = {};// 한 프로퍼티씩 각각 설정Object.defineProperty(person, 'fullName', {value: '홍길동',writable: true// 💡 누락한 어트리뷰트는 기본값으로 자동생성});Object.defineProperty(person, 'name', {get () {return this.fullName.split('').map((letter, idx) => idx === 0 ? letter : '*').join('');}});console.log(person, person.name);console.log( // ⚠️ 누락된 어트리뷰트들 확인해볼 것Object.getOwnPropertyDescriptors(person));// 여러 프로퍼티를 객체 형식으로 한꺼번에 설정Object.defineProperties(person, {ageInNumber: {value: 25,writable: true},age: {get () { return this.ageInNumber + '세'; },set (age) {this.ageInNumber = Number(age);}}});person.age = 30;console.log(person, person.age);console.log(Object.getOwnPropertyDescriptors(person));
III. 적용예
const person = {fullName: '홍길동',ageInNumber: 25,};// 💡 value를 전우치로 바꾸면Object.defineProperty(person, 'fullName', {value: '전우치'});console.log(person);console.log(Object.keys(person));// 💡 enumerable을 false로 바꾸면Object.defineProperty(person, 'fullName', {enumerable: false});console.log(Object.keys(person));console.log(// ⭐️ Object의 또 다른 정적 메서드// ⭐️ enemerable이 false인 프로퍼티도 반환Object.getOwnPropertyNames(person));console.log(Object.getOwnPropertyDescriptors(person));// 💡 seal: configurable을 false로 바꿈Object.seal(person);console.log(Object.getOwnPropertyDescriptors(person));console.log(Object.getOwnPropertyDescriptors(person));// 💡 freeze: configurable과 writable을 false로 바꿈Object.freeze(person);console.log(Object.getOwnPropertyDescriptors(person));
IV. 깊은 동결 deep freeze
- 재귀적으로 객체를 가장 깊숙히까지 동결
- 🔗 MDN 문서의 deepFreeze 예시와는 달리, 주어진 인자 자체를 변형하지 않도록
function getDeepFrozen(obj) {console.log(obj);const result = {};const propNames = Object.getOwnPropertyNames(obj);for (const name of propNames) {const value = obj[name];result[name] =(value && typeof value === 'object') ?getDeepFrozen(value) : value;}return Object.freeze(result);}let myObj = {a: 1,b: {c: 2,d: {e: 3,f: {g: 4}}}}// 여러 번 실행해 볼 것myObj.a++;myObj.b.c++;myObj.b.d.e++;myObj.b.d.f.g++;console.log(myObj);// 💡 실행 뒤 바로 위의 출력 코드를 다시 실행해 볼 것myObj = getDeepFrozen(myObj);'웹 > JavaScript' 카테고리의 다른 글