Object properties configuration

김상연·2022년 12월 6일

JavaScript

목록 보기
11/19

configuration은 리눅스 운영체제를 처음 접했을 때 때 참 많이 마주치던 단어다. 객체의 속성도 configure-able 하다니..

1. property flags and descriptor

일반적으로는 드러나지 않지만, 객체의 속성에는 3가지 설정사항이 있다. 이것들을 flags라고 부른다.

세 가지 모두 기본값은 true이다.

  • writable : 값이 수정 될 수 있는지 말한다.
  • enumerable : loop의 요소로 쳐줄지 아닐지 말한다.
  • configurable : 속성이 삭제 될 수 있는지, 그리고 이 flags들이 수정 될 수 있는지 말한다.

객체의 속성, 이 속성의 flags와 더불어 value 까지 4가지 속성을 가진 객체를 descriptor라고 부른다. 이것을 통해 flags에 접근하고 수정 할 수 있다. 확인하는(읽는) 방법은 아래와 같다.

// 	Object.getOwnPropertyDescriptor(obj, propertyName); 
//	위 메소드는 obj의 propertyName 속성의 descriptor를 반환한다.

let user = {
  name: "John"
};

const descriptor = Object.getOwnPropertyDescriptor(user, 'name');

console.log(descriptor);

//  { value: "John",
//  writable: true,
//  enumerable: true,
//  configurable: true }

descriptor를 수정하려면 다른 메소드가 필요하다. 아래 예시를 통해 확인해 봐라. 상연아 집중해라

Object.defineProperty(user, 'name', {
	value: 'Kim',
    writable: false
})

예시에서 보다시피 값 자체도 바꿀 수 있다.

flags의 설정을 무시하는 구문을 실행하면 오류가 발생할까?

  • strict mode : 오류가 발생하고 프로세스가 멈춘다.
  • non-strict mode : 오류는 발생하지 않지만 구문은 무시된다.

enumerable : false인 경우 for ..in 구문이나 Object.key 메소드에서 제외 된다.

configurable은 one-way road다. 한번 false로 만든 뒤에는 삭제도, configure도 할 수 없다. 그러나 값은 여전히 수정 할 수 있다. writable 플래그가 참이라면 말이다.

헌데 configurable : false 일 때에도 flag를 딱 한 가지 경우엔 수정 할 수 있는데, wrtiable : true -> flase인 경우다 . 이 경우는 값을 한층 더 보호하는 행위라서 허용된다고 이해 할 수 있다. 물론 그 반대는 불가능하다.

일반적인 방법으로 객체를 복사하면 flags까지 복사되지 않는다. 이것이 필요하다면 아래처럼 가능하다.

//	메소드들이 복수형인 것에 주목한다. 각 메소드는 배열을 리턴하고 배열을 매개변수로 받는다.
let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));

지금까지 어떤 객체에 속한 각각의 속성을 관리하는 방법들이었다. 당연히 객체 자체를 관리하는 방법도 있다. 실제로 사용하는 경우는 거의 없지만 원체 간단하니 읽어나 두자.

Object.preventExtensions(obj)
: Forbids the addition of new properties to the object.

Object.seal(obj)
: Forbids adding/removing of properties. Sets configurable: false for all existing properties.

Object.freeze(obj)
: Forbids adding/removing/changing of properties. Sets configurable: false, writable: false for all existing properties.

위 상태들을 확인 해 볼 수도 있다.

Object.isExtensible(obj)
: Returns false if adding properties is forbidden, otherwise true.

Object.isSealed(obj)
: Returns true if adding/removing properties is forbidden, and all existing properties have configurable: false.

Object.isFrozen(obj)
: Returns true if adding/removing/changing properties is forbidden, and all current properties are configurable: false, writable: false.

2. data property VS. accessor property

우리가 흔히 보는 객체의 속성은 data property이다. 좀 더 정확히 말해보자면 descriptor

  • value
  • writable
  • enumerable
  • configurable

로 구성된 속성이다.

그에 반해 accessor property descriptor는 다음과 같이 구성되어 있다.

  • get : 객체의 속성을 읽을 때 실행되는 함수. 매개변수는 없다.
  • set : 객체의 속성에 할당 연산을 하면 실행되는 함수. 할당 연산의 우항 값을 매개변수로 가진다.
  • enumerable
  • configurable

예를 들면 아래와 같다.

let user = {
  name: "John",
  surname: "Smith"
};

Object.defineProperty(user, 'fullName', {
  get() {
    return `${this.name} ${this.surname}`;
  },

  set(value) {
    [this.name, this.surname] = value.split(" ");
  }
});

console.log(user.fullName); // John Smith

for(let key in user) console.log(key); // name, surname

gettersetter는 함수이기 때문에 조건을 다는 등 유연하게 쓸 수도 있다.

let user = {
  get name() {
    return this._name;
  },

  set name(value) {
    if (value.length < 4) {
      console.log("최소 4글자 이상으로 할당하세요.");
      return;
    }
    this._name = value;
  }
};

user.name = 'Kim' 	//	undefined, 최소 4글자 이상으로 할당하세요.

위 예시에서 user._name 속성에도 접근 할 수 있다. 그러나 널리 알려진 관습의 하나로, 객체 안에 underscore("_")로 이름 짓는 속성은 일종의 내부속성으로 여기고 외부에서 접근하지 않는다. getter를 이용하도록 하자.

profile
리눅스와 컴퓨터 프로그래밍

0개의 댓글