JavaScript

[자바스크립트] 프로퍼티 어트리뷰트(Property Attribute)

문승주 2023. 5. 10. 02:01
반응형

 내용은 이웅모 님의 모던 "자바스크립트 DeepDive" 책을 보고 정리한 내용입니다. 저작권 보호를 위해 책의 내용은 요약되었습니다.

 

내부슬롯과 내부 메서드

 

- 내부슬롯과 내부 메서드는 JavaScript 엔진의 구현 알고리즘을 설명하기 위해 ECMScript 사양에서 사용하는 의사 프로퍼티와 의사 메서드이다.

 

- JavaScript 엔진 내부적으로 사용되며, 일부 객체의 동작을 구현하는 데 사용된다.

 

- 일반적으로 내부 슬롯과 메서드는 JavaScript 코드에서 직접 접근할 수 없지만 내부 슬롯의 경우 __proto__를 통해 간접적으로 접근할 수 있다.

- 모든 객체는 [[Prototype]] 내부 슬롯을 가지며, 이는 객체의 프로토타입 체인을 구성하는 데 사용된다. 이 슬롯은 일반적으로 접근할 수 없지만, ES6에서는 Object.getPrototypeOf() 함수를 사용하여 간접적으로 접근할 수 있다.

- 내부 메서드에는 [[Get]], [[Set]], [[OwnPropertyKeys]] 등이 있고, 이들은 객체의 속성을 읽거나 쓰는 데 사용된다.

 

 

 

프로퍼티 어트리뷰트와 프로퍼티 디스크립터 객체

- JavaScript에서 객체 속성은 프로퍼티 어트리뷰트(Property Attribute)를 가지며, 이 어트리뷰트는 속성의 동작을 지정한다. 프로퍼티 어트리뷰트는 Object.defineProperty() 또는 Object.defineProperties() 함수를 사용하여 직접 설정할 수 있다.

- 프로퍼티 디스크립터 객체(Property Descriptor Object)를 사용하여 프로퍼티 어트리뷰트를 설정할 수 있는데 프로퍼티 디스크립터 객체는 속성의 정보를 담고 있는 객체로, 다음과 같은 속성을 가질 수 있습니다.

1. 데이터 프로퍼티(Data Property)

데이터 프로퍼티는 키와 값으로 구성된 일반적인 속성으로 값을 저장하고 가져오는 역할을 하며 프로퍼티 생성시 기본값으로 자동 정의된다.

네, 객체의 속성은 다음과 같이 정리할 수 있습니다.

[[Value]] 속성의 키를 통해 값에 접근하면 반환되는 값이다.
[[Writable]] 속성의 값을 변경할 수 있는지 여부를 나타내며 boolean 값을 갖는다.
[[Enumerable]] 속성이 for...in 루프 등을 통해 열거 가능한지 여부를 나타내며 boolean 값을 갖는다.
[[Configurable]] 속성이 삭제하거나 속성 어트리뷰트를 변경할 수 있는지 여부를 나타내며 boolean 값을 갖는다.
let person = {
  name: 'John',
  age: 30
};

2. 접근자 프로퍼티(Accessor Property)

접근자 프로퍼티는 데이터 프로퍼티와 달리 값을 직접 저장하지 않으며, 대신 값을 가져오는 getter와 값을 설정하는 setter 함수를 사용하여 값을 처리한다.

[[Get]] 속성 값을 가져오는 getter 함수이다.
[[Set]] 속성 값을 설정하는 setter 함수이다.
[[Enumerable]] 속성이 for...in 루프 등을 통해 열거 가능한지 여부를 나타낸다.
[[Configurable]] 속성이 삭제하거나 속성 어트리뷰트를 변경할 수 있는지 여부를 나타낸다.
let person = {
  firstName: 'John',
  lastName: 'Doe',
  get fullName() {
    return this.firstName + ' ' + this.lastName;
  },
  set fullName(name) {
    let names = name.split(' ');
    this.firstName = names[0];
    this.lastName = names[1];
  }
};

 

객체 변경 방지

1. 객체 확장 금지(Object.preventExtensions)

Object.preventExtensions 메소드는 객체에 새로운 프로퍼티를 추가할 수 없도록 설정한다. 하지만, 이미 존재하는 프로퍼티의 값은 변경할 수 있다. 이 때, [[Extensible]] 프로퍼티가 false로 변경된다.

 

let person = { name: 'John', age: 30 };

Object.preventExtensions(person);

person.gender = 'Male'; // 무시됨 (strict mode에서는 TypeError 발생)

console.log(person); // { name: 'John', age: 30 }
console.log(Object.isExtensible(person)); // false

 

2. 객체 밀봉(Object.seal)

Object.seal 메소드는 객체에 새로운 프로퍼티를 추가하거나, 이미 존재하는 프로퍼티의 속성을 변경하거나 삭제할 수 없도록 설정한다. 이 때, [[Extensible]] 프로퍼티가 false로 변경되고, 모든 존재하는 프로퍼티의 [[Configurable]] 프로퍼티가 false로 변경되므로 밀봉된 객체는 읽기와 쓰기만 가능하다.

 

let person = { name: 'John', age: 30 };

Object.seal(person);

delete person.age; // 무시됨 (strict mode에서는 TypeError 발생)
person.gender = 'Male'; // 무시됨 (strict mode에서는 TypeError 발생)
person.name = 'Mike'; // 가능

console.log(person); // { name: 'Mike', age: 30 }
console.log(Object.isSealed(person)); // true

 

3. 객체 동결(Object.freeze)

Object.freeze 메소드는 객체에 새로운 프로퍼티를 추가하거나, 이미 존재하는 프로퍼티의 속성을 변경하거나 삭제할 수 없도록 설정하고, 존재하는 모든 프로퍼티의 [[Writable]] 프로퍼티를 false로 변경한다. 이 때, [[Extensible]] 프로퍼티가 false로 변경되고, 모든 존재하는 프로퍼티의 [[Configurable]] 프로퍼티가 false로 변경되므로 동결된 객체는 읽기만 가능하다.

 

let person = { name: 'John', age: 30 };

Object.freeze(person);

delete person.age; // 무시됨 (strict mode에서는 TypeError 발생)
person.gender = 'Male'; // 무시됨 (strict mode에서는 TypeError 발생)
person.name = 'Mike'; // 무시됨 (strict mode에서는 TypeError 발생)

console.log(person); // { name: 'John', age: 30 }
console.log(Object.isFrozen(person)); // true

 

4. 불변객체(Immutable Object)

불변객체(Immutable Object)는 객체 생성 후 객체의 상태를 변경할 수 없는 객체로 이러한 객체는 생성 이후에는 추가, 삭제, 수정이 불가능하며, 객체 내부의 프로퍼티들도 불변한다. 대신, 객체를 변경하는 대신에 새로운 객체를 생성하거나 복사해서 원하는 상태를 만들 수 있다.

 

const obj = {
  name: 'John',
  age: 30,
  address: {
    street: '123 Main St',
    city: 'New York',
    state: 'NY'
  }
};
function deepFreeze(obj) {
  // 객체 동결
  Object.freeze(obj);

  // 모든 프로퍼티를 순회하며 중첩된 객체를 동결
  Object.getOwnPropertyNames(obj).forEach(function(prop) {
    const propValue = obj[prop];
    if (typeof propValue === 'object' && propValue !== null) {
      deepFreeze(propValue);
    }
  });

  return obj;
}

const frozenObj = deepFreeze(obj);
반응형