Object.create(...)でオブジェクトを作る（シリーズその５）

「必要なのはJavaScript言語仕様書とブラウザーコンソールだけ！」
シリーズ、その５。

#Object.create で最も単純なオブジェクトを作る

[Object.create](http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.3.5) 関数の仕様によると、
引数として渡されたプロトタイプを持つオブジェクトを生成するとあり、Nullも渡せると書いてある。

できるだけ単純なオブジェクトから作ってみることにする。

##Nullを渡してオブジェクトを作ってみる。

```js
var o1 = Object.create(null)
o1
```

![2015-12-09 19_07_13-Cortana.png](https://qiita-image-store.s3.amazonaws.com/0/103139/48c558a2-73da-f39b-aa10-59651ea18459.png)

問題なく作れた。これはいったいどういうオブジェクトなんだろう。

##オブジェクトのプロトタイプを調べる
では、[Object.getPrototypeOf()](http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.3.2) 関数を使って、o1のプロトタイプを調べてみる。
予想はNullが返される。

```js
Object.getPrototypeOf(o1)
```

![2015-12-09 19_09_59-Start.png](https://qiita-image-store.s3.amazonaws.com/0/103139/e1679d99-29e5-cafe-3044-0f11d5711057.png)

結果は予想どおり。

さて、このプロトタイプが無い（Nullな）オブジェクトだけど、一体役に立つのだろうか？

#プロトタイプを持たないオブジェクトの性質

[prototype の利用目的](http://www.ecma-international.org/ecma-262/5.1/#sec-4.2.1)は継承とプロパティの共有なので、逆に言うとprototypeを持たないオブジェクトはそのどちらも利用出来ないということになる。

コンソールに

```js
var o1 = Object.create(null)
o1.toString()
```

っと打ち込むと

![2015-12-09 19_26_33-Start.png](https://qiita-image-store.s3.amazonaws.com/0/103139/7b28b7b5-8e95-4c36-8047-64a2a8657577.png)

このように怒られてしまう。`toString()`なんてありませんよ、と言っている。

なぜこうなるかというと、o1は「プロパティの共有」で toString をどこかから探してくる、ということが出来ないからである。

o1はこの状態だと誰からも何も継承しないし共有もしないので、全くもって役に立たない、天涯孤独な寂しいオブジェクトを作ってしまったわけだ・・・

#プロトタイプを持たないオブジェクトにせめて自分だけのプロパティを！

誰ともプロパティを共有していないからといって、自分専用のプロパティを持ってはいけない、ということにはならない。

[Object.defineProperty()](http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.3.6) 関数を使って新しくプロパティを加えてあげよう。

```js
var o1 = Object.create(null)
Object.defineProperty(o1, "id", {value : 123});
o1.id
```

![2015-12-09 19_36_21-Start.png](https://qiita-image-store.s3.amazonaws.com/0/103139/e596c9f2-830f-ed63-20a1-ef3fae492051.png)

idという独自のプロパティを持たせることが出来た。

こうやってちまちまとオブジェクトをほぼゼロから定義していくやり方もある。可能だしJavaScriptの理解の助けにはなるが、実際的には役に立ちそうにない。

#Null以外で単純なオブジェクトを作る

プロトタイプがNullだとつまらないので、せめてObjectオブジェクトのプロトタイプを指定して新規オブジェクトを作ってみる。

```js
var o2 = Object.create(Object.prototype)
o2.toString()
```

![2015-12-09 19_47_26-Start.png](https://qiita-image-store.s3.amazonaws.com/0/103139/1eeb4fda-f171-c707-7eb1-18a7030fd417.png)

今度はtoStringという名前のプロパティが見つかった。呼び出しが成功し、オブジェクトをStringで表す値が返されている。さて、このtoString関数は一体どこから継承してきたのかというと、それはo2のプロトタイプである Object.prototype からである。

ちょっとややこしくなって来たけど、コンソールで確認してみる。

```js
Object.getPrototypeOf(o2) == Object.prototype
```

結果：

![2015-12-09 19_49_48-Start.png](https://qiita-image-store.s3.amazonaws.com/0/103139/8a5e8e8a-1fac-80ca-0e2b-b18e2f3eb67f.png)

o2のプロトタイプはObject.prototypeと同じだと出た。
当然といえば当然。何しろ

```ja
var o2 = Object.create(Object.prototype)
```

と指定したわけだから。

**要点**
`Object.create`にprototypeを渡すと、それをプロトタイプとするオブジェクトを生成してくれる。

#誰がそのプロパティを持っているか？

継承とか共有が起こると、そもそも誰のモノなのか、といったあたりで混乱が起こりやすい。とくにバグで予想外の結果が出る場合は、想定されていないオブジェクトのプロパティが使われていたりする可能性がある。

[Object.getOwnPropertyNames(O)](http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.3.4) を使って、オブジェクトが独自に定義しているプロパティをリストアップすることが出来る（リストが空の場合もありうる）

以下、コンソールでo2と、そのプロトタイプであるObject.prototypeそれぞれのプロパティをそれぞれリストアップさせてみる。

```js
Object.getOwnPropertyNames(o2)
Object.getOwnPropertyNames(Object.prototype)
```

結果：

![2015-12-09 19_56_08-Start.png](https://qiita-image-store.s3.amazonaws.com/0/103139/c63aeb72-310c-1388-53fe-edeb7b2f2be0.png)

o2は何も独自に定義していないので、返された値は要素ゼロの列。
対して、Object.prototype の方はいくつものプロパティを定義しているのが分かる。

そして `toString`はObject.prototypeしか定義していなから、`o2.toString()`はそれを継承することになる。

**要点**
オブジェクトは、そのオブジェクトのprototypeのプロパティを継承する。

ということはJavaScriptプログラミングではprototypeのプロパティにどんなものがあるのかを知ることが重要になってくる。Object.prototypeも含めて built-inオブジェクトのprototypeをより理解することが大切だということだ。

#built-inオブジェクトのprototypeを調べる

ここではいくつかの built-in オブジェクトのprototypeを`Object.getOwnPropertyNames`を使って見てみる。
JavaScript関連の本やリファレンスを見ても分かることだが、コンソールと対話式で調べた方が便利な場合も多いかもしれない。

調べるプロトタイプは：

* Object.prototype
* Function.prototype
* String.prototype
* Array.prototype

**Object.prototype**

```
> Object.getOwnPropertyNames(Object.prototype)
< ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__", "__lookupSetter__", "__proto__"]
```

最もよく使う`toString`メソッドはここで定義されている。
`hasOwnProperty`や`isPrototypeOf`などは動的に型を扱えるJavaScriptの特徴的なメソッドだと言える。

**Function.prototype**

```
Object.getOwnPropertyNames(Function.prototype)
["length", "name", "arguments", "caller", "constructor", "bind", "toString", "call", "apply"]
```

もっとも関数らしいメソッドが`call`。他にも`name`や`arguments`、そして`caller`なんてものもある。
この中で特に興味深いのは`bind`メソッド。これは後述するが、オブジェクトのインスタンスとFunctionオブジェクトと深い係わりがある。

**String.prototype**

```
Object.getOwnPropertyNames(String.prototype)
["length", "constructor", "valueOf", "toString", "charAt", "charCodeAt", "codePointAt", "concat", "endsWith", "includes", "indexOf", "lastIndexOf", "localeCompare", "match", "normalize", "repeat", "replace", "search", "slice", "split", "substring", "substr", "startsWith", "toLowerCase", "toLocaleLowerCase", "toUpperCase", "toLocaleUpperCase", "trim", "trimLeft", "trimRight", "link", "anchor", "fontcolor", "fontsize", "big", "blink", "bold", "fixed", "italics", "small", "strike", "sub", "sup"]
```

文字数を返す`length`はよくあるプロパティ。
`startsWith`、`endsWith`、`includes`などのサーチ系もあるが、`match`という、正規表現を使用する強力なものもある。
`toLowerCase`や`toUpperCase`などのトランスフォーム系、それに`concat`や`split`などのC++やC#でお馴染みの便利メソッドがあるのが分かる。

**Array.prototype**

```
Object.getOwnPropertyNames(Array.prototype)
["length", "constructor", "toString", "toLocaleString", "join", "pop", "push", "reverse", "shift", "unshift", "slice", "splice", "sort", "filter", "forEach", "some", "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight", "entries", "keys", "copyWithin", "find", "findIndex", "fill", "concat", "includes"]
```

C++やC#に慣れている人にとっては`pop`や`push`それに`concat`などは軽い驚きを与える。それらの言語では Array は要素数が固定されているの、それをスタックのように使うには別のデータストラクチャーを使わなくてはならない。JavaScriptのArrayはより柔軟だということが分かる。

`find`や`findIndex`などのサーチ系は一般的。
`forEach`を使ってそれぞれの要素をインデックスなどを使わずに処理することもできる。

**要点**
built-in オブジェクトのprototypeのプロパティを知ることがJavaScriptプログラミングの基礎になる。


（つづく）