# 객체의 속성 설정

---

## 개요

자바스크립트의 객체 property들은 각각의 설정값들을 지닌다.

일반 설정과 데이터 접근 설정으로 나뉘는데, 이 속성 정의에 따라 property의 쓰임이 달라진다. 

**공통**

**configurable**: 설정 재조정과 프로퍼티 삭제 여부 / 기본값 false

**enumerable**: 열거 여부 (in Object.keys(), or for-in statement) / 기본값 false

**일반 설정자**

**value**: 프로퍼티의 값 / 기본값 undefined

**writable**: true 일 경우 값을 할당할 수 있다. / 기본값 false

**접근 설정자 (Getter, Setter)**

**get**: 속성값을 얻는 함수이다. 즉 해당 속성의 값을 리턴한다. / 기본값 undefined

**set**: 속성값을 설정하는 함수이다. 인자는 value하나만 올 수 있다. / 기본값 undefined

### Object.defineProperty(), 공통, 일반 설정자

Object 생성자의 static 메소드인 definedProperty는 이러한 객체의 설정들을 세부적으로 조정할 수 있도록 돕는다. 용법은 다음과 같다.

```
Object.defineProperty(obj, prop, descriptor)
```

첫번째 인자인 obj는 메소드의 대상이 되는 객체이다. 두번째 인자 prop은 설정할 프로퍼티의 이름이며, 마지막 인자 descriptor에서 이 설정들을 객체의 형태로 조정한다. 이를테면, 다음과 같다.

```
const obj = {};
Object.defineProperty(obj, 'foo', {
  __proto__: null,
  value: 'bar'
  writable: true
});

console.log(obj)
```

value, writable외의 기타 설정이 없으므로 모두 default설정으로 들어간다. 즉 configurable, enumerable 속성이 모두 false인 것이다. 다음 코드를 실행해보자.

```
obj.foo = 1; 
console.log(obj) // 안 바뀜, writable 불가

Object.defineProperty(obj, 'foo', {
  __proto__: null,
  value: 'foobar',
}); // CANNOT REDEFINE PROPERTY 에러, configurable이 false이기 때문

Object.defineProperty(obj, 'foo', {
  writable: false;
}); // 단, writable 값만은 configurable == false 라도, 오직 false 로는 바뀔 수 있다

for(let i in obj) {
  console.log(i) 
}

Object.keys(obj)

// 둘 다 빈값으로 나옴, enumerable이 false이기 때문
```

그렇다면 객체 리터럴로 생성한 프로퍼티의 경우는 어떨까?

```
const obj2 = {
  foo: 'this is writable, enumerable, and configurable!!'
}

obj2.foo = 'is this writable, enumerable, and configurable ?'
console.log(obj2.foo)
// writable!!

for (let i in obj2) {
  console.log(i)
}

console.log(Object.keys(obj2))
// enumerable!

Object.defineProperty(obj2, 'foo', {
  value: '...'
}) // configurable !!
```

재선언, 열거, 재설정이 모두 가능하다. 즉 객체 리터럴로 생성한 프로퍼티는 다음과 같다.

```
const obj2 = {
  foo: 'bar'
}

// 는 다음과 같다.

Object.defineProperty(obj2, 'foo', {
  value: 'bar',
  writable: true,
  enumerable: true,
  configurable: true
})
```

### 접근 설정자

접근 설정자는 getter, setter를 의미한다. 일반적으로 사용하는 getter, setter함수는 이 속성의 축약형이다.

접근 설정자는 writable속성이나, value 속성과 같은, value를 다루는 속성과는 함께 쓰일수 없다. 즉 다음과 같은 코드는 에러가 난다.

```
const obj3 = {}
let temp = 0;
Object.defineProperty(obj3, 'foo', {
  value: 0,
  writable: true,
  get (){
    return temp;
  }
});
// TypeError: Invalid property descriptor. 
// Cannot both specify accessors and a value or writable attribute
```

Getter나 Setter는 다음 형태로도 사용이 가능하다 (es6 Proxy로도 비슷한 동작을 만들 수 있다)

```
function Archiver() {
  let temp = null;
  const archive = [];

  Object.defineProperty(this, 'temp', {
    get() {
      console.log('get!');
      return temp;
    },
    set(value) {
      temp = value;
      archive.push({ val: temp });
    }
  });

  this.getArchive = () => archive;
}

const arc = new Archiver();
arc.temp = 'temp1';
arc.temp = 'temp2';

arc.getArchive();
```

위의 예에서 볼 수 있듯 Getter나 Setter를 사용하면 사용자가 객체를 추가하거나, 변경할 때 임의의 설정이 가능하다. 이러한 특성을 이용해 Vue와 같은 프레임워크에서는 Reactivity, 즉 반응성을 정의한다.

### 참고

[https://v2.ko.vuejs.org/v2/guide/reactivity.html](https://v2.ko.vuejs.org/v2/guide/reactivity.html) 

[반응형에 대해 깊이 알아보기 — Vue.js](https://v2.ko.vuejs.org/v2/guide/reactivity.html)

For the site tree, see the [root Markdown](https://slashpage.com/develop.md).
