x.map is not a function
 Author: 水卜

mapができない

配列に対してmapしたはずなのに
x.map is not a function
と怒られることがある。

document.getElementsByTagName('h2').map(i => i.textContent);
> VM17827:1 Uncaught TypeError: document.getElementsByTagName(...).map is not a function at <anonymous>:1:37

この時mapを掛けようとした相手をよく見るとHTMLCollectionとある。

document.getElementsByTagName('h2');
> HTMLCollection(3) [h2, h2, h2]

スプレッド演算子を使ってこう書くと、配列を返してくれる。mapも使える。

[...document.getElementsByTagName('h2')].map(i => i.textContent);

iterableだけどArrayではない

iterable=反復可能。
for文でループできたり、スプレッド演算子で中身を展開できたりする。
以下詳細。
iterableプロトコル

つまりdocument.getElementsByTagNameの結果はiterableなオブジェクトではあるが、Arrayではない。

mapが使える状況

mapと呼んでいるメソッドは、正確にはArray.prototype.map()を指す。
prototypeはjsで継承を実現するときに使われる。
親クラスのprototypeに関数を定義し、子クラスのprototypeにスーパークラスのインスタンスを渡すと子は親の関数を引き継ぐ。

function Super() {}
Super.prototype.hello = 'hello';

var Sub = function() {}
Sub.prototype = new Super();

var instance = new Sub();
instance.hello // 10

つまり、Arrayを継承しているオブジェクトだけがmapを使うことができる。
冒頭の例でHTMLCollectionオブジェクトは、iterableではあるがArrayを継承していなかった。