コンストラクタだってapplyしたい

posted in: JavaScript | 0

松山事務所の石丸です。

以前JavaScriptで可変長引数を受け取って別の関数へ渡したいという記事で、普通の関数をapplyしましたが、コンストラクタをapplyするにはどうしたらよいか調べていたら、stack overflowでとてもいい記事に出会えました。
今回もES5.1です。

試行錯誤

まずは自力でいろいろ試してみました。

ポチもジョンもコンストラクタじゃないと怒られてしまいます。
太郎はただ戻り値のない関数を呼び出しただけなので taroundefined になってしまいました。

コンストラクタといってもそれ自体はただの関数なので、new演算子とapplyをどう組み合わせるかというところがキモですね。

「Function.prototype.bindを使うと良い感じに書けるぜ」

stack overflow – Use of .apply() with ‘new’ operator. Is this possible?
ここで一番人気の回答が次のコードです。

何が起こるのかわからない魔法のようなコードですが、
この回答にはとても丁寧な補足解説があるのでグーグル翻訳を駆使してこのコードを理解していきます。

補足解説翻訳

限られた数の引数を取る関数に対してnewを実行する必要があります。
bindメソッドを使うと、次のようにすることができます。

newキーワードがfのコンテキストをリセットするので、anythingパラメータはあまり重要ではありませんが、構文上の理由から必要です。
可変引数を渡す必要があるので、ちょっとしたトリックを使います。

それを関数で囲みましょう。 Clsはarugment 0として渡されるので、それは anything に相当します。

一時的な変数 f は必要ありません。

Cls.bindが上書きされている可能性があるので、Function.prototype.bindで置き換えると、最終的に回答のコードになります。

機械翻訳感が残っていますが伝わりますよね?

補足

トリックの部分が結構大事です。
newCallという関数にすることでnewCallの第一引数のClsがうまいことbindの第一引数になっているので、関数にしない場合はapplyの第二引数の配列(のようなオブジェクト)の先頭には anything に相当するなにかを渡してあげる必要があります。

LINEで送る
Pocket