レッスンに戻る

同じコンストラクタでオブジェクトを作成する

重要度: 5

コンストラクタ関数によって作成された任意のオブジェクトobjがあるとします。どのような関数によって作成されたかはわかりませんが、それを使用して新しいオブジェクトを作成したいと思います。

このようにできますか?

let obj2 = new obj.constructor();

そのようなコードが正しく機能するobjのコンストラクタ関数の例と、正しく機能しない例の例を挙げてください。

"constructor"プロパティが正しい値を持っていることを確信している場合、このようなアプローチを使用できます。

たとえば、デフォルトの"prototype"に触れない場合、このコードは確実に機能します

function User(name) {
  this.name = name;
}

let user = new User('John');
let user2 = new user.constructor('Pete');

alert( user2.name ); // Pete (worked!)

機能したのは、User.prototype.constructor == Userだったためです。

…しかし、「言い換えれば」誰かがUser.prototypeを上書きし、Userを参照するようにconstructorを再作成するのを忘れた場合、失敗します。

例えば

function User(name) {
  this.name = name;
}
User.prototype = {}; // (*)

let user = new User('John');
let user2 = new user.constructor('Pete');

alert( user2.name ); // undefined

user2.nameundefinedなのはなぜですか?

new user.constructor('Pete')の仕組み:

  1. 最初に、user内にconstructorを探します。ありません。
  2. 次に、プロトタイプチェーンに従います。userのプロトタイプはUser.prototypeであり、constructorもありません(正しく設定することを「忘れた」ためです)。
  3. チェーンをさらに遡ると、User.prototypeはプレーンオブジェクトで、そのプロトタイプは組み込みのObject.prototypeです。
  4. 最後に、組み込みのObject.prototypeの場合、組み込みのObject.prototype.constructor == Objectがあります。そのため、これを使用します。

最後に、let user2 = new Object('Pete')になります。

おそらく、それが私たちが求めていることではありません。new Userを作成したいのであって、new Objectではありません。これは、constructorがないことの結果です。

(念のためですが、new Object(...)の呼び出しはその引数をオブジェクトに変換します。これは理論的なことで、実際には new Objectを値で呼び出す人はおらず、一般にオブジェクトを作成するために new Objectを使用することはありません。