new 演算子と Construct 内部メソッド
var o1 = [], f1 = function(){ return o1; }; (new f1()) === o1; // true var o2 = 1, f2 = function(){ return o2; }; (new f2()) === o2; // false
これってどういうことだってばよ? という話。
例によって仕様から解説してみようかと。
new 演算子
new 演算子自体は実は大したことはしていない。
- 対象が function であること
- 対象の function に
[[Construct]]
内部メソッドがあること [[Construct]]
を呼び出した結果を返す
要するに[[Construct]]
が肝である。
[[Construct]] 内部メソッド
- 空オブジェクト obj を作成
- obj の [[Prototype]] にコンストラクタのprototypeプロパティをセット
- obj が this となるようにコンストラクタをcallし結果を result にセット
- result が Object なら result を返す
- obj を返す
だいたいこんな流れ。最後の条件分岐が今回の肝。
最初のコードに戻ると、f1 では Arrayオブジェクト(typeof [] === "object")を返すのでそれを返し、f2 ではプリミティブなnumberを返すので、それは無視されて作成したobjを返すという仕組になっている。
コードにしてみる
言葉で書くと、分かりにくいかもしれないのでコードにしてみる。
Function.prototype.new = function () { var obj = Object.create(this.prototype); var result = this.apply(obj, arguments); if (typeof result === "object") return result; return obj; };
こんな感じ。