[JS] なんとなく分かった気になっているJSをはっきりしておく ~ Object オブジェクト Part 2 ~

Object オブジェクトのPart 1に続き、Part 2です！
### Object.create(prototype, プロパティー達)
```js
var obj = {}; // Object.create(Object.prototype)と同じ意味となります
var obj2 = Object.create(null, {
    a: {
        writable: true,
        configurable: false,
        value: 5,
    }
});

obj2.a; // 5
```
createの意味通り、オブジェクトを生成する方法の一つです！
プロパティー達のところのオプションには`writable、 configurable、 enumerable、 get、 set、 value`があり、詳しい話は下記の`defineProperties`を見てください！

### Object.defineProperties(オブジェクト, プロパティー達)、        Object.defineProperty(オブジェクト, プロパティー, 説明)
```js
var obj = {};
Object.defineProperties(obj, {
    a: {
        writable: false,
        enumerable: true, 
        value: 5,
    },
    b: {
        get: function() {
            return 'yuchan';
        },
        set: function(value) {
            console.log(this.value);
            this.a = value;
        },
        enumerable: false,
        configurable: false,
    },
});
obj.a; // 5
obj.b; // 'yuchan'
obj.a = 10;
obj.a; // 5 <-- writableがfalseなため更新されてない
for (var key in obj) {
    console.log(key); 
}; // a undefined <-- bはenumerableがfalseなためlogには出力されない！

obj.b = 15; // 15に更新される代わりsetの内容が実行されるsetのvalueは15となる
obj.a; // 5 <-- this.a = valueにより15に更新されるベキだが、writableがfalseなためそのまま
obj.b; // 'yuchan'
Object.defineProperty(obj, 'b', {
    value: 5
}); // Uncaught TypeError: Cannot redefine property <-- configurableがfalseなため再定義できない
```
オブジェクトのプロパティーを詳しく定義できます！

`writable`はプロパティーの値を更新できるかどうか、`enumerable`は`for..in`ループ文内で使用できるか、`configurable`はプロパティーの説明を更新できるかを設定できます。falseの場合は`delete`での削除もできなくなります。デフォルト値として`writable、 enumerable、 configurable`は`false`となっております。`value`はプロパティーの値、`get`はプロパティーの値を取得する時、`set`はプロパティーの値を設定の時を意味します！

`writable`はプロパティーの値が更新されることを防ぎますが、値がオブジェクトの場合はそのオブジェクト内のプロパティーが更新されるのは防げません！

これを防ぐには後で紹介する`Object.freeze`というメソッドがあります。
```js
Object.defineProperty(obj, 'c', {
    value: { x: 3, y: 4 },
    writable: false,
    enumerable: true,
});
obj.c; // { x: 3, y: 4 }
obj.c = 'yuchan';
obj.c = // { x: 3, y: 4 }
obj.c.x = 5;
obj.c = // { x: 5, y: 4 } <-- writableがfalseでもオブジェクト内のプロパティーは更新できる
```

### Object.getOwnPropertyDescriptor(オブジェクト, プロパティー)
```js
Object.getOwnPropertyDescriptor(obj, 'b'); // {enumerable: false, configurable: false, get: ƒ, set: ƒ}
```
プロパティーの説明を取得できます！

### Object.freeze
```js
var frozenObj = Object.freeze(obj);
frozenObj.a = 10;
frozenObj.a; // 5
delete frozenObj.c; // false
Object.freeze(obj.c); // これで内部のオブジェクトも完全に更新を防げる
```
上記の例で、`writable`が`false`でも値がオブジェクトなら、そのオブジェクトのプロパティーまでは更新できることがわかりました。

ここで、`Object.freeze`を使えばオブジェクト全体を更新できないように固定できます！
値も更新できず、プロパティーの追加および削除もできず、プロパティーの説明も更新できません！

### Object.seal
```js
var sealedObj = Object.seal(obj);
sealedObj.a = 10;
sealedObj.a; // 5 <-- writableがtrueなら10に更新されていた
delete sealedObj.c; // false
```
`seal`の場合プロパティーの追加および削除はできず、`configurable`が`false`に変更されます。

代わりに`freeze`と違ってプロパティーの値は`writable`が`true`なら更新できます！

### Object.preventExtensions
```js
var nonExtensible = Object.preventExtensions(obj);
nonExtensible.d = 'new';
nonExtensible.d; // undefined
```
プロパティーの追加だけ防ぎたい時に使うのがこの`Object.preventExtensions`です！
その他のプロパティーの削除や値の更新、オブション設定の更新などは可能です。

### Object.keys
```js
Object.keys(obj); // ['a', 'c'] <-- 'b'はenumerableがfalseなため除かれている
```
こちらはよく目にするメソッドですよね！
オブジェクトで`enumerable`が`false`のプロパティーを除いたプロパティーを全て持ってきて、そのまま配列に変えてくれます！

### typeof
```js
var a = 1;
var b = 'yuchan';
var c = true;
var d = {};
var e = [];
var f = function() {};
var g;
var h = null;

typeof a; // 'number'
typeof b; // 'string';
typeof c; // 'boolean';
typeof d; // 'object';
typeof e; // 'object';
typeof f; // 'function';
typeof g; // 'undefined'
typeof h; // 'object';
```
対象の型を確認する時に使用します！
しかし、配列と`null`も`object`という型で表示されるため、配列を見分けるためには`Array.isArray`メソッドを使用して、nullを見分けるためには別の処理が必要になってきます。(`null`も`object`になるのは流石にJavaScript側のミスかなと思いますw)

### delete
```js
var obj = {
  a: 'hi',
  b: 'yuchan',
};
obj.b; // yuchan
delete obj.b;
obj.b; // undefined
```
オブジェクト内のプロパティーを削除できます！
成功すれば`true`を失敗したら`false`を返します。

先ほども書きましたが、`configurable`が`false`か`Object.freeze`でオブジェクトが固定されている状態であれば失敗します。