【js】x.map is not a functionの解決方法とそれから理解したこと

# 概要
javascriptでmapメソッドを使いたかったが以下のエラーが出てきたのでメモ。
配列っぽいデータを加工したい場合はmapメソッドを使っとけばいい、と思っていたが、それは曖昧な理解ですべての場合で使えるわけではなかったので、問題の解決とともにしっかりと掘り下げてみた。

```
Uncaught TypeError: x.map is not a function
```

# 今回やろうとしたこと
inputタグを利用してファイルを複数選択できるようにし、そのファイル群をmapメソッドで処理するというもの。
ただ、今回のケースと違っていても同じ考え方で解決できる問題はあるはず。

```html:ファイルを複数選択する単純なもの
<html>
  <body>
    <input type="file" multiple onchange="selectFile()" id="file"/>
  </body>
</html>
```

# わかったこと
##なぜmapが使えなかったか。
そもそも私が何気なく利用していたmapは`Array.prototype.map()`というものであった。
`Array.prototype`ってなに、となるがこれはプロトタイプチェーンや型の構造について理解すれば解決する。[この記事](https://qiita.com/howdy39/items/35729490b024ca295d6c)が理解の助けになった。
mapメソッドを利用するためには操作対象のオブジェクトがmapメソッドを持つ、もしくは`__proto__`プロパティがmapメソッドを持つ必要がある。Array型のオブジェクトは`__proto__`プロパティにmapメソッドを持つためmapをすることができる。このことが前述の
>私が何気なく利用していたmapは`Array.prototype.map()`というものであった。

という部分を説明してくれている。

今回私が操作したいデータをみてみると以下のデータであり、Arrayではないし、FileListの`__proto__`プロパティにmapメソッドが定義されていないためmapが使えないのも納得である。しかしFileListは頑張れば繰り返し処理をさせられそうな形である。であれば、どうすればmapを利用可能にできるかが知りたい。

```
FileList {0: File(147802), 1: File(370312), length: 2}
```

とりあえず調べてみると[stackoverflow](https://stackoverflow.com/questions/44511925/how-to-map-through-an-array-of-input-files)にそれらしいことが書いてあったので一部を引用する。

>FileList is not an Array, and does not inherit from Array, but it does implement the iterable protocol, so you can use the spread syntax to get it as an array.

FileListは`iterable protocol`を実装しているらしい。そして`spread syntax`を使えばArrayとしてデータを取ってこられるらしい。私には`iterable protocol`と`spread syntax`がわからなかったが、この2つの単語を理解できれば解決もすぐそこだと思うので、もう少し調べることにした。

# `iterable protocol`とはなんなのか。
[MDN - 反復処理プロトコル](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols)の抜粋だが下記のように述べられている。
>iterable (反復可能)プロトコルによって、JavaScriptオブジェクトは、for..of構造で値がループしているもの等の反復動作を定義、または、カスタマイズできます。ArrayやMapのように、いくつかのビルトインの型はデフォルトの反復動作を持っているビルトイン iterables です。一方、(Objectのような)他の型は反復動作を持ちません。 

簡単に言うと`iterable protocol`を実装していることは反復可能、であるということがわかる。同記事の[反復可能オブジェクトを期待する構文](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols#Syntaxes_expecting_iterables)に述べられているが、以下の方法で`iterable protocol`を実装したオブジェクトの値を取得することができる。

```
// 例1
for(let value of ["a", "b", "c"]){
    console.log(value);
}
// "a"
// "b"
// "c"

// 例2
[..."abc"]; // ["a", "b", "c"]
```

この例2を見てみると`[...変数]`の形式を利用すると配列を取得できることがわかる。
これにより`Iterable protocol`を実装しているがArrayオブジェクトではないFileListオブジェクトはArrayオブジェクトに無事に変換できることがわかる。

# `spread syntax`とはなんなのか
[MDN - スプレッド構文](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax)を見ると明らかになったが、先の「`iterable protocol`とはなんなのか。」で登場した例2のコードがまさにこれである。3点リーダーで変数を展開することを`spread syntax`という、これだけのことである。

これで以下の文言をしっかりと理解することができた。
>FileList is not an Array, and does not inherit from Array, but it does implement the iterable protocol, so you can use the spread syntax to get it as an array.

そして私はこれを駆使して無事にFileList型からmapメソッドを利用できるようになった。

# その他
## Iterableか確認する
これも先ほどから抜粋している[stackoverflow](https://stackoverflow.com/questions/44511925/how-to-map-through-an-array-of-input-files)で述べられているが操作対象のオブジェクトがIterableであるかは

```
変数名[Symbol.iterator]()
```
で確認することができる。

# 参考
https://stackoverflow.com/questions/44511925/how-to-map-through-an-array-of-input-files
https://qiita.com/howdy39/items/35729490b024ca295d6c
http://lightbulbcat.hatenablog.com/entry/2018/02/04/060811
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols#Syntaxes_expecting_iterables
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax