JavaScript を書いてる人はおそらく普段このようなコードでクラスとインスタンスを記述するかと思います。
var Hoge = function (foo, bar) {
this.foo = foo;
this.bar = bar;
};
var hoge = new Hoge('hello', 'world');
しかし、ES5 で導入された Object.create()
でこのオブジェクトを複製すると、Firefox や WebKitのコンソールで Object
と出力されてしまいます。
実際には プロトタイプチェーンを引き継いでいますし、以下のような実行結果になります。
var hogeClone = Object.create(hoge);
console.log(hogeClone.constructor === Hoge); // true
console.log(hogeClone instanceof Hoge); // true
これは、var
による変数に無名の function リテラルでコンストラクタを宣言している場合に起きる現象です。デバッガがオブジェクトのコンストラクタを認識する時に、hoge.constructor.name
を参照するので、無名関数リテラルではその値が空と判断され、「それじゃあ出力で表示するクラス名は タダのObject
でいいね」と判断するためです。
console.log(hoge.constructor.name); // ""
ちゃんとデバッガがクラス名を出力するパターン
var Hoge = function Hoge(foo, bar){
this.foo = foo;
this.bar = bar;
};
// Firefox の Firebug だと、これでもダメ。
// function Hoge () {} と完全に function 文にする必要あり。
var hoge = new Hoge('hey!', 'you!');
console.log(hoge.constructor.name); // "Hoge"
このようにリテラルでなく、文としてコンストラクタを宣言すると、デバッガは function.name を参照してインスタンスをクラス名で表示してくれるようになります。
「実行に影響ないよね?」← やり方によってはあるよ
function 文で書いてしまうと、スコープの一番先頭に移動されるので、リテラルでの宣言と挙動が変わるケースは存在します。
しかし、大抵の場合、クラスのコンストラクタ宣言でそうした影響の可能性はほぼ無いかと思われます。(別にコンストラクタがグローバルリークするわけでもないし、宣言した箇所のスコープは保持するので)
特に var Hoge = function Hoge() {}
のように名前つき function リテラル で宣言する場合はほとんど影響ないです。
じゃあ、してもしなくてもあんまり変わらないのかというと、デバッグしやすさにおいてかなり影響があります。
すべて var
でコンストラクタを定義してあると、せっかくクラスを定義して、メソッドやプロトタイプを当て、役割を決めているのにデバッガですべて Object
として出力されてしまってはもったいないですよね。