質問: 「javascript逆引きレシピ」の073pにて、クラス(コンストラクタ)を定義することに関する情報が記載されているのですが、そのクラスを学ぶ際の注意点として、コンストラクタは自動的にthisの指すオブジェクトを返すので返り値はいらないと記述してありました。つまり、インスタンスのもとになる関数は、そのインスタンスを自動的に返すから戻り値はいらないということだと思うのですが、書いてある意味がいまいちわからないのです。 注意を促している箇所で記述されているので、何か大切な理由があると思うのですが、理解できません。 ちなみに、返り値やインスタンスという単語の意味は理解しているつもりですが、このように上記の文章になると何を伝えたかったのか理解できなくなります。
回答: 仕様書を確認したところ、かなり複雑な動作をするようです。`new F(args)`とした場合、最終的に`F.[Construct]`が呼び出されるのですが、この`[[Construct]]`は内部メソッド(JavaScriptの内部処理だけに使われるメソッド、コードには現れない)であり、他の関数とは異なる特殊な動作をします。 参考: ECMAScript 2015 9.2.2 Construct ざくっと動作の概要を説明すると、Fのオブジェクトを作成してそれを`this`にbindしたF()を評価した後に、 1. return文で終わっているとき 1-1. returnの結果がObject型であれば、その結果を返す。 1-2. そうではなく、Fが基本型(派生型では無い)であれば、**作成したFのオブジェクト**を返す。 1-3. そうではなく、returnの結果がundefinedで**なければ**、*TypeError例外を発生させる*。 2. 1でない、または、1-1〜1-3のどれでもなければ、**作成したFのオブジェクト**を返す。 という動作をします(厳密ではありませんし、詳しいところまで見てないので間違いがあるかも知れません)。つまり、Fのコンストラクタが`return {};`で終わっていれば、`new F(args)`は`{}`返しますが、Fが基本型で`return 0;`などで終わっていれば、0ではなくFのオブジェクトが返します。そもそもreturn文がない、または、`undefined`を返すのであれば、Fのオブジェクトを返します。 なお**派生(derived)型**以外の全てのクラス(関数)は全て**基本(base)型**です。派生型はECMAScript 2015のclass構文で`extends`を使った場合とジェネレーター以外は無いようです。functionのみを使ったECMAScript 5までの書き方(babel等で変換した場合も同様)であれば、TypeError例外が発生する事は無いので、気にしなくても良いようです。 まとめると`new`演算子でオブジェクトを生成した場合、返ってくる値は下記の通りです。 1. コンストラクタに値を指定したreturn文がなければ、新たに作成されたそのクラスのオブジェクトが返ります。 2. コンストラクタに値を指定したreturn文があれば、 2-1. return文で指定した値がObject型であれば、その**指定した値**が返ります。 2-2. それ以外なら、return文がない場合と同じです。 2-3. ただし、ECMAScript 2015からのclass構文を使っていると**例外が発生する**場合があります。 法則が複雑で混乱の元なので、値を指定したreturn文は書かない(return文そのものがない、または、`return;`※のみ)のがいいでしょう。 ※`return;`は`return undefined;`と同じですが、その場合も、必ず作成したオブジェクトが返り、例外も発生しません。