なぜArray.prototype.push.applyで配列が結合できるのか

posted in: JavaScript | 0

松山事務所の石丸です。
JavaScriptで配列Aに対して配列Bを結合する場合、MDNのArray.prototype.pushによるとArray.prototype.pushを使って次のように書くことができます。

なぜ vegetables.push(moreVegs); ではなく、Array.prototype.push.apply なのでしょうか?

そもそもArray.prototype.pushとは

push() メソッドは、配列の末尾に 1 つ以上の要素を追加することができます。また戻り値として新しい配列の要素数を返します。

MDN: Array.prototype.pushより

Array.pushは配列を受け取れるわけではありません。1つ以上の要素、つまり可変長引数を取ります。
TypeScript的に型を付けてArrayクラスのpushメソッドを書くと
push(elementOrElements: any | any[]): number
ではなく
push(...elements: any[]): number
なんです。

これを勘違いしてしまうとvegetables.pushでmoreVegsを結合するようなコードを書いてしまい、
要素数が3で、3番目の要素が配列オブジェクトの vegetables が出来上がります。

Array.prototype.pushは渡された引数が何かなんて気にしていません。
渡されたものをただ後ろにくっつけるだけです。

Function.prototype.applyとは

apply() メソッドは与えられた this 参照値と、配列(もしくは配列風のオブジェクト)の形で与えられた引数を用いて関数を呼び出します。

MDN: Function.prototype.applyより

以前 JavaScriptで可変長引数を受け取って別の関数へ渡したいの記事でも使用しましたが、可変長引数を受け取る関数にはFunction.prototype.applyを使って、配列のようなオブジェクトを渡すことができます。

可変長引数を受け取る関数 Array.prototype.push
配列のようなオブジェクト moreVegs

この時のapplyの第一引数 thisArg に vegetables を渡してやれば、

のコードは

と等価になります。

配列を結合したいなんて初学者でもよくあることだと思うのですが、
いきなり Function.prototype.apply とか出てきたらびっくりしませんかね?

LINEで送る
Pocket