【ITニュース解説】Never asked JavaScript interview question 🤪 How will you create an object of class from other object Normal way - const jack = new Person(); //using class name find a way to create tom object without using class name Person
2025年10月04日に「Dev.to」が公開したITニュース「Never asked JavaScript interview question 🤪 How will you create an object of class from other object Normal way - const jack = new Person(); //using class name find a way to create tom object without using class name Person」について初心者にもわかりやすく解説しています。
ITニュース概要
JavaScriptでオブジェクトを作る際、通常はクラス名を用いる。しかし、既存のオブジェクトからそのクラス名を使わずに、同じクラスの新しいオブジェクトを生成する方法がある。これは、知っておくと便利なJavaScriptの一歩進んだテクニックだ。
ITニュース解説
JavaScriptの学習を進める中で、オブジェクト指向プログラミングの概念に触れる機会は多い。クラスを定義し、そのクラスから新しいオブジェクト(インスタンス)を生成する方法は、プログラミングの基本的な操作だ。通常、この操作は「new演算子」と「クラス名」を組み合わせて行う。例えば、Personというクラスがあれば、const jack = new Person();のように記述することで、jackというPersonクラスの新しいオブジェクトが生成される。これは非常にシンプルで直感的な方法で、多くのプログラマーが日常的に利用している。
しかし、JavaScriptの奥深さを探求すると、一見すると奇妙に思えるような、しかし深い理解を要求する問いに出会うことがある。今回解説する記事は、まさにそのような問いを提示している。「既存のオブジェクトから、そのオブジェクトが属するクラス名を直接使わずに、同じクラスの新しいオブジェクトを生成するにはどうすれば良いか?」という問いだ。具体的には、jackというPersonクラスのオブジェクトが既に存在する場合、Personというクラス名をコード中に記述せずに、jackと同じPersonクラスのtomというオブジェクトを生成する方法を探る、というものだ。
この問題は、単にオブジェクトを生成するだけでなく、JavaScriptの「プロトタイプ継承」という核となるメカニズムへの理解を深めることを促す。通常のオブジェクト生成方法では、開発者がクラス名を把握しており、それを直接記述できることが前提となる。しかし、現実の複雑なアプリケーション開発では、生成したいオブジェクトのクラス名が動的に決定されたり、あるいはコードの抽象度を高めるために特定のクラス名に依存したくない場面が出てくることがある。例えば、外部から渡されたオブジェクトに対して、そのオブジェクトが何らかのクラスのインスタンスであることはわかるが、具体的にどのクラスなのかはコード上で明示的に書きたくない、といったケースだ。このような状況で、クラス名を直接指定せずに同じ型の新しいオブジェクトを生み出す方法を知っていることは、柔軟で保守性の高いコードを書く上で非常に役立つ。
では、どのようにしてこの課題を解決するのか。鍵となるのは、JavaScriptのオブジェクトが持つ「プロトタイプ」という概念と、それを取得するためのメソッドだ。
すべてのJavaScriptオブジェクトは、内部的に「プロトタイプ」という別のオブジェクトへの参照を持っている。このプロトタイプは、そのオブジェクトが持つべきメソッドやプロパティのひな形を提供する役割を果たす。そして、クラスから生成されたオブジェクトの場合、そのプロトタイプは、元のクラスの「コンストラクタ関数」への参照を含んでいる。
ここで登場するのが、Object.getPrototypeOf()という組み込みメソッドだ。このメソッドは、引数として与えられたオブジェクトのプロトタイプを返す。例えば、jackというオブジェクトのプロトタイプを知りたい場合、Object.getPrototypeOf(jack)と記述する。この結果返されるプロトタイプオブジェクトは、実は元のクラスのコンストラクタ関数への参照をconstructorプロパティとして持っている。
つまり、Object.getPrototypeOf(jack).constructorと記述することで、私たちはjackオブジェクトを生成した元のPersonクラスの「コンストラクタ関数」そのものを取得できるのだ。このコンストラクタ関数は、クラスのインスタンスを生成するための特殊な関数だと考えることができる。
そして、この取得したコンストラクタ関数を、通常のクラス名と同じようにnew演算子と組み合わせて使用すれば、新しいオブジェクトを生成できる。
具体的には、const tom = new (Object.getPrototypeOf(jack).constructor)();と記述することで、Personというクラス名を直接使わずに、jackと同じPersonクラスの新しいオブジェクトtomが生成される。ここで(Object.getPrototypeOf(jack).constructor)全体を括弧で囲んでいるのは、new演算子に渡す対象が関数(この場合はコンストラクタ関数)であることを明確にするためだ。
この方法は、jackがPersonクラスのインスタンスであるかぎり、jackがどんなオブジェクトであっても、そのオブジェクトと同じクラスの新しいインスタンスを生成できるという点で非常に強力だ。jackがもしStudentクラスのインスタンスであれば、同じ方法でStudentクラスの新しいインスタンスを生成できる。コード中に特定のクラス名をハードコードする必要がなくなるため、より汎用的なコードを書くことが可能になる。
このような一見複雑な方法がなぜ必要なのか、システムエンジニアを目指す初心者には疑問に思うかもしれない。その理由は、ソフトウェア開発における「柔軟性」と「拡張性」を追求するためだ。
- 動的なクラスの生成: 実行時にどのクラスのオブジェクトを生成すべきか決まるようなシナリオでは、このテクニックが非常に有効だ。例えば、ユーザーの入力に基づいて異なる種類のオブジェクトを生成するような場合、事前にすべてのクラス名を列挙して条件分岐する代わりに、既存のオブジェクトから動的にコンストラクタを取得することで、より簡潔で柔軟なコードを書ける。
- リファクタリングへの対応: コードのリファクタリング(改善)でクラス名が変更された場合でも、この方法を使っていれば、オブジェクト生成部分のコードを修正する必要がなくなる。クラス名への直接的な依存をなくすことで、変更に強いコードになる。
- デザインパターンの実装: ファクトリパターンなどのデザインパターンを実装する際にも、この手法は利用されることがある。ファクトリは、具体的なクラス名を隠蔽しつつ、オブジェクト生成のロジックを一箇所にまとめる役割を果たすが、その内部でこのように動的にコンストラクタを取得してオブジェクトを生成することが可能だ。これにより、新しいクラスが追加されてもファクトリのコードを大きく変更する必要がなくなる。
- フレームワークやライブラリの開発: 大規模なフレームワークやライブラリでは、ユーザーが定義したカスタムクラスのインスタンスを、フレームワーク側が動的に生成する必要がある場面がある。そのような場合、具体的なクラス名を知らずともインスタンスを生成できるこのテクニックは不可欠となる。
システムエンジニアを目指す初心者にとって、この問題はJavaScriptの表面的な使い方だけでなく、その内部構造と仕組みへの理解を深める良い機会となる。
- オブジェクトとプロトタイプ: JavaScriptのオブジェクト指向は、「クラスベース」というよりは「プロトタイプベース」という側面が強い。
Object.getPrototypeOf()のようなメソッドを通して、オブジェクトがどのようにしてその性質や振る舞いを受け継いでいるのか(プロトタイプ継承)を理解することは、JavaScriptを深く学ぶ上で不可欠だ。 - コンストラクタ関数の役割: クラスが実体として何をしているのか、
new演算子が具体的にどのような処理を行っているのかを理解する上で、コンストラクタ関数が果たす役割を知ることは重要だ。クラスは、実質的にはコンストラクタ関数とそれに紐づくプロトタイプオブジェクトのシンタックスシュガー(書き方を簡略化したもの)として実装されている。 - 動的なプログラミングの概念: クラス名を直接書かずにオブジェクトを生成できるという事実は、JavaScriptが非常に動的な言語であることの一例だ。実行時にプログラムの振る舞いを変更したり、未知の型に対応したりする能力は、現代のソフトウェア開発において非常に価値が高い。
- 抽象化の重要性: 特定のクラス名に依存せず、既存のオブジェクトからその型情報を取得して新しいオブジェクトを生成するというアプローチは、「抽象化」というプログラミングの重要な概念を体現している。具体的な実装の詳細(この場合はクラス名)からコードを切り離すことで、より汎用性が高く、変更に強いコードが書けるようになる。
このように、一見すると「変な問題」に見えるかもしれないが、この問いはJavaScriptの根幹にあるメカニズム、そしてより高度なプログラミング手法へとつながる重要な示唆を含んでいる。単にコードが動くかどうかだけでなく、その裏側で何が起きているのか、なぜそのような動作をするのかを深く探求する姿勢が、優れたシステムエンジニアになるための第一歩となるだろう。