얼레벌레

모던자바스크립트 Deep Dive - 16장 프로퍼티 어트리뷰트 본문

JavaScript/모던자바스크립트 Deep Dive

모던자바스크립트 Deep Dive - 16장 프로퍼티 어트리뷰트

낭낭이 2022. 3. 26. 17:00

자바스크립트에는 개발자가 직접적으로 접근하지 못하는, 엔진의 내부 조직인 내부 슬롯과 내부 메서드가 존재함

- 내부 슬롯과 내부 메서드는 이중 대괄호([[...]])로 감싸져 있는 것들에 해당함

- 간접적으로 일부는 접근 가능 (ex) [[prototype]] → __proto__로 접근 가능

 

프로퍼티 어트리뷰트

* js엔진은 프로퍼티 생성 시 프로퍼티 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의

✔️ 프러퍼티 상태 - 프로퍼티 값([[Value]]), 값의 갱신 가능 여부([[Writable]]), 열거 가능 여부([[Enumerable]]), 재정의 가능 여부([[Configurable]])

Object.getOwnPropertyDescriptor(s)() : 프로퍼티 어트리뷰트를 간접적으로 확인하는 메서드로 프로퍼티 디스크립터 객체를 반환함

const person = {
  name:'ny',
  age:23,
}

console.log(Object.getOwnPropertyDescriptor(person,'name')) //{value: 'ny', writable: true, enumerable: true, configurable: true}


// Object.getOwnPropertyDescriptors 메서드로 모든 프로퍼티의 프로퍼티 디스크립터 객체 반환 가능

console.log(Object.getOwnPropertyDescriptors(person)) 
/*{
    "name": {
        "value": "ny",
        "writable": true,
        "enumerable": true,
        "configurable": true
    },
    "age": {
        "value": 23,
        "writable": true,
        "enumerable": true,
        "configurable": true
    }
}
*/

 

프로퍼티는 데이터 프로퍼티와 접근자 프로퍼티로 구분 가능

데이터 프로퍼티

 

접근자 프로퍼티

 

프로퍼티 정의

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

✔️ Object.defineProperty() : 프로퍼티 어트리뷰트 정의

🔻 디스크립터 객체 누락시 undefined/false로 정의된다 → value, set, get은 undefined로 writable, enumerable, configurable은 false로 지정됨

const person={};

Object.defineProperty(person, 'firstName', {
    value: 'Kim',
    writable: true,
    enumerable: true
}) 

console.log(person) // {firstName: 'Kim'}

// Object.defineProperties 메서드로 한번에 여러개의 프로퍼티 정의
const person={};

Object.defineProperties(person,{
    'firstName':{
        value: 'Kim',
        writable:true,
        enumerable:true,
        configurable:false
    },
    'lastName':{
        value:'ny'
    }})
    
console.log(person) // {firstName: 'Kim', lastName: 'ny'}

// 디스크립터 객체 누락시 undefined나 false(기본값)으로 지정된다
console.log(Object.getOwnPropertyDescriptor(person,'lastName')) 
// {value: 'ny', writable: false, enumerable: false, configurable: false}
// value외에 지정하지 않은 어트리뷰트들은 false 기본값으로 정의됨

 

객체 변경 방지

🔸 얕은 변경 방지 

- 얕은 변경 방지인 객체 확장금지, 객체 밀봉, 객체 동결은 직속 프로퍼티만 변경을 방지하고 중첩 객체는 영향을 미치지 못한다.

▪️ 객체 확장 금지 : 프로퍼티 추가 불가 ✅ Object.preventExtensions() : 객체 확장 금지 / isExtensible() : 확장 가능 여부 확인

const person={name:'ny'};

console.log(person) // {name: 'ny'}
console.log(Object.isExtensible(person)) // true

Object.preventExtensions(person)
console.log(Object.isExtensible(person)) // false => 객체 확장 금지됨

// 객체 확장 금지로 프로퍼티 추가 금지 => 에러없이 무시됨
person.age=23;
console.log(person) // {name: 'ny'}

// 프로퍼티 정의에 의한 프로퍼티 추가도 금지
Object.defineProperty(person,'age',{value:23}) // Uncaught TypeError 발생

▪️ 객체 밀봉 : 프로퍼티 추가, 삭제, 재정의 불가. 즉, 읽기와 쓰기만 가능  ✅ Object.seal() : 객체 밀봉 / isSealed() : 밀봉 여부 확인

const person={name:'ny',
  age:23,
}

console.log(person) // {name: 'ny', age: 23}
console.log(Object.isSealed(person)) // false

Object.seal(person) // 객체 밀봉
console.log(Object.isSealed(person)) // true

// 프로퍼티 추가, 삭제, 어트리뷰트 재정의 불가 (기존값 갱신은 가능)
// 에러없이 무시됨
person.job='student'
console.log(person) // {name: 'ny', age: 23}

delete person.name;
console.log(person) // {name: 'ny', age: 23}

▪️ 객체 동결 : 프로퍼티 추가, 삭제, 재정의, 쓰기 불가. 즉, 읽기만 가능 ✅ Object.freeze() : 객체 동결 / isFrozen() : 동결 여부 확인

const person={name:'ny',
  age:23,
}

console.log(person) // {name: 'ny', age: 23}
console.log(Object.isFrozen(person)) // false

Object.freeze(person) // 객체 동결
console.log(Object.isFrozen(person)) // true

// 프로퍼티 추가, 삭제, 어트리뷰트 재정의, 값갱신 금지(읽기만 가능)
// 에러없이 무시됨

person.name='jh'
console.log(person.name) // 'ny'

🔸 불변 객체

❗️ 얕은 객체 변경 방지는 중첩 객체까지 동결을 하지 못한다. 따라서 이 경우 모든 프로퍼티에 재귀적으로 얕은 변경 방지 메서드를 호출해야 함

const person={name:'ny',
  age:23,
  address:{city:'seoul',district:'gangnam'},
}

Object.freeze(person)
Object.isFrozen(person) // true
Object.isFrozen(person.name) // true
Object.isFrozen(person.address) // false => 중첩 객체까지 동결 X

person.address.city = 'incheon'
console.log(person.address.city) // 'incheon'

// 재귀적으로 Object.freeze 메서드 호출
function deepFreeze(target){
  if (target && typeof target == 'object' && !Object.isFrozen(target)) {
    Object.freeze(target);
    Object.keys(target).forEach(key => deepFreeze(target[key]));
  }
  return target;
}

const person={name:'ny',
  age:23,
  address:{city:'seoul',district:'gangnam'},
}

deepFreeze(person)

Object.isFrozen(person) // true
Object.isFrozen(person.address) // true

person.address.city = 'incheon'
console.log(person.address.city) // 'seoul' => 중첩 객체까지 동결됨
Comments