プロパティ記述子のDataDescriptorの各プロパティをよく分かっていないためまとめた

[JavaScript Advent Calendar 2015](http://qiita.com/advent-calendar/2015/javascript)の19日目の記事です。
JavaScript初心者のため勉強中。

# プロパティ記述子とは
ある本を読んでいたのだが、こんなようなことが書かれていた。

> JavaScriptでのオブジェクトは「名前」と「値」の組み合わせである__プロパティ__の集合。（中略）厳密にはプロパティ名と属性群の組み合わせで、これらの属性のセットを__プロパティ記述子__という。

…はい？属性群？
よく分からんし、見たことない。

とりあえず`getOwnPorpertyDescription`メソッドで設定内容を参照できるらしいので確認。

```js
var obj = {};
obj.a = 1;
Object.getOwnPropertyDescriptor(obj, "a");

// 結果
Object {
    value: 1, 
    writable: true, 
    enumerable: true, 
    configurable: true
}
```

ほー、なんかvalue以外にもwritable, enumerable, configurableとか設定されとるが、わしそんなもの設定しとらんぞ？というわけで各属性の特徴を調べてみた。

# DataDescriptorの各属性の説明
- Value 　→　文字通り値。

- Writable 　→　Value属性を更新できるか否かを指定。

- Enumerable 　→　for-in文で補足するか否かを指定。

- Configurable 　→　プロパティ記述子を変更できるか否かを指定。（ただしWritable以外）

頭を大文字で記載したが、使う時は小文字で使うルールらしい。
以下、各属性の使い方。（Value属性は省く）

### Writable属性
オブジェクトを定義し、value, wraitableを設定。

```js
// オブジェクトの定義
obj = {};

// プロパティ"a"の設定
Object.defineProperty(obj, "a", {
    value: 1,
    writable: false
});

// プロパティ"b"の設定
Object.defineProperty(obj, "b", {
    value: "hoge",
    writable: true
});

console.log(obj.a);
console.log(obj.b);

// プロパティ"a"のvalueを変更
obj.a = 200;
// プロパティ"b"のvalueを変更
obj.b = "fuga";

console.log(obj.a);
console.log(obj.b);


// 結果
1
hoge
1
fuga
```

はい、aでは`value`が更新されないこと、bでは更新されることが確認できた。
ちなみに、この後もう一度`defineProperty`メソッドから`writable`を`true`に変更しようとしたが、エラーとなった。一度定義すると後からは変更できないらしい。

※指定しないとデフォルトで`false`に設定される。

### Enumerable属性
オブジェクトを定義し、それをfor-in文で表示してみると、なんか余計なものが表示される。

```js
// プロパティ"hoge"の設定
Object.prototype.hoge = function() { console.log("fuga") };
// オブジェクトの定義
var obj = {};

for (var key in obj){ console.log(key) };

// 結果
hoge
undefined
```

ん？`hoge`が表示されている。 これがいわゆる__オブジェクト汚染__というやつか。
これを回避するために`Enumerable`属性を`false`にするといいと。

```js
// プロパティ"hoge"の設定
Object.defineProperty(Object.prototype, "hoge",{
    value: function() { console.log("fuga") },
    enumerable: false
});

// オブジェクトの定義
var obj = {};

for (var key in obj) { console.log(key) };
obj.hoge();

// 結果
undefined
fuga
```

よし。これで`for-in`文では`undifined`が表示され、`obj.hoge()`にて`fuga`が表示された。

### Configure属性
オブジェクトを定義し、それを更新・削除してみる。

```js
// オブジェクトの定義
var obj = {};
// プロパティ"hoge"の設定
Object.defineProperty(Object.prototype, "hoge",{
    value: 1,
    enumerable: false,
    configurable: false
});

// "hoge"プロパティの属性確認
Object.getOwnPropertyDescriptor(obj, "hoge");


// "hoge"プロパティの更新
Object.defineProperty(obj, "hoge", {
    enumerable: true,
    configurable: true,
    writable: true
});
// "hoge"プロパティの属性確認
Object.getOwnPropertyDescriptor(obj, "hoge");


// "hoge"プロパティの削除
delete obj.hoge;
// "hoge"プロパティの属性確認
Object.getOwnPropertyDescriptor(obj, "hoge");


// 結果
Object {
    value: 1, 
    writable: false, 
    enumerable: false, 
    configurable: false
}

TypeError発生
Object {
    value: 1, 
    writable: false, 
    enumerable: false, 
    configurable: false
}

false
Object {
    value: 1, 
    writable: false, 
    enumerable: false, 
    configurable: false
}
```

よし。こちらも各属性を更新しようとするとTypeErrorとなり、プロパティが削除されないことが確認できた。

※1 初期設定でconfigurableをtrueにしていた場合、変更できることも確認済み。
※2 一度falseにすると、今後更新できないことも確認済み。

# 終わりに
今回はデータプロパティのみ扱ったが、アクセサプロパティと言うものも存在し、そちらでは`Get, Set`関数を持つ。
プロパティ記述子の活用法はまだ模索段階らしく、この時はこれを使う、という体系化はなされていないそうな。まぁ使う頻度はそんなにはなさそうだが、知っていて損はないかな。

※何か間違っている記述がございましたら、ご指摘いただけますと幸いです！