UXPに備えてモダンなJSの書き方に慣れる(配列のような振る舞いをするオブジェクト、Arrayオブジェクト)
配列のような配列
jsには配列のようで配列でないオブジェクトもあります。一見妙に聞こえるかもしれませんがECMA3で代表的なものと言えばargumentsでしょう。
引数の値を配列のように引き受けるarguments。for文で反復可能なので一見配列型のオブジェクトに見えます。しかし。
forEachを使用するとエラーが出てしまいました。なぜでしょうか?
本当にArray型なのか確かめてみる。
ECMA5からArrayオブジェクトはArray.isArrayメソッドで確認可能です。Array型のオブジェクトならtrue、それ以外はfalseを返します。
以下確かめてみます。
なんとfalseが返ってきました。つまりargumentsはfor文で反復可能でlengthプロパティも持っているので配列のような振る舞いをしますが実はArrayオブジェクトではないのです。念のためクラス名も確かめてみましょう。
argumenntsはArgumentsというクラス名を返しました。このarguments、配列のような振る舞いをしますがArrayオブジェクトから継承されたオブジェクトではないのでArrayメソッドが使えないのです。これはargumentsに限った話ではなくhtml要素を取得する時にgetElementsByClassNameメソッドやquerySelectorAllメソッドから取得するHTMLCollectionやNodeListの時も同様です。これらは反復可能なオブジェクトなのでまるで配列のような振る舞いをしますがArrayオブジェクトから継承されたオブジェクトではありません。
それではこれらのオブジェクトをArray型にするにはどうすれば良いでしょうか?関数の引数についてはECMA2015より残余引数構文が追加されました。使いた方はargumentsとほとんど同じです。異なるのは引数名の前に…と付け加えるだけです。渡された引数をArray型で引き受けます。
argumentsと違ってArrayコンストラクトのインスタンスオブジェクトなのでArrayメソッドが使えます。
勿論残余引数のより前の位置でしたら単体での引数も受け取れます。
HTMLCollectionやNodelistのような場合はArray.fromメソッド、もしくわシャローコピー で簡単にArray型のオブジェクトに変換可能です。
このケース以外にも配列のような振る舞いをするオブジェクトが存在するかもしれません。特に今後UXPによる開発でいろんな型のオブジェクトを扱うことになると思います。Arrayメソッドが使えない、という時はArray.isArrayによる型の確認をすると良いでしょう。