constructor プロパティは、インスタンスオブジェクトを生成した Object のコンストラクター関数への参照を返します。なお、このプロパティの値は関数そのものへの参照であり、関数名を含んだ文字列ではありません。値が 1, true, "test" のようなプリミティブ値の場合は読み取り専用です。
説明
(Object.create(null) で生成されたオブジェクトを除いて) すべてのオブジェクトが constructor プロパティを持ちます。明示的にコンストラクター関数を用いることなく生成されたオブジェクト (つまり、オブジェクトや配列のリテラル) は、 constructor プロパティがそのオブジェクトの基礎オブジェクトのコンストラクター型を指します。
var o = {};
o.constructor === Object; // true
var o = new Object;
o.constructor === Object; // true
var a = [];
a.constructor === Array; // true
var a = new Array;
a.constructor === Array; // true
var n = new Number(3);
n.constructor === Number; // true
例
例: オブジェクトのコンストラクターの表示
以下の例では、コンストラクターである Tree と、その方のオブジェクトである theTree を生成します。そして、 theTree オブジェクトの constructor プロパティを表示します。
function Tree(name) {
this.name = name;
}
var theTree = new Tree('Redwood');
console.log('theTree.constructor is ' + theTree.constructor);
この例の出力は次のとおりです。
theTree.constructor is function Tree(name) {
this.name = name;
}
例: オブジェクトのコンストラクターの変更
次の例は、一般的なオブジェクトのコンストラクターの値を変更する方法を示しています。 true, 1, "test" については、コンストラクターが読み取り専用のネイティブのものであるため影響を受けません。この例は、オブジェクトの constructor プロパティに頼ることが常に安全とは限らないことを示しています。
function Type () {}
var types = [
new Array(),
[],
new Boolean(),
true, // 変わらない
new Date(),
new Error(),
new Function(),
function () {},
Math,
new Number(),
1, // 変わらない
new Object(),
{},
new RegExp(),
/(?:)/,
new String(),
'test' // 変わらない
];
for (var i = 0; i < types.length; i++) {
types[i].constructor = Type;
types[i] = [types[i].constructor, types[i] instanceof Type, types[i].toString()];
}
console.log(types.join('\n'));
この例の出力は次の通りです (参考にコメントを追加しています)。
function Type() {},false, // new Array()
function Type() {},false, // []
function Type() {},false,false // new Boolean()
function Boolean() {
[native code]
},false,true // true
function Type() {},false,Mon Sep 01 2014 16:03:49 GMT+0600 // new Date()
function Type() {},false,Error // new Error()
function Type() {},false,function anonymous() {
} // new Function()
function Type() {},false,function () {} // function () {}
function Type() {},false,[object Math] // Math
function Type() {},false,0 // new Number()
function Number() {
[native code]
},false,1 // 1
function Type() {},false,[object Object] // new Object()
function Type() {},false,[object Object] // {}
function Type() {},false,/(?:)/ // new Regexp()
function Type() {},false,/(?:)/ // /(?:)/
function Type() {},false, // new String()
function String() {
[native code]
},false,test // 'test'
関数のコンストラクターの変更
多くの場合、このプロパティは new およびプロトタイプ継承チェーンで将来の呼び出しに使われる関数コンストラクターとしての関数の定義に使用されます。
function Parent() {}
Parent.prototype.parentMethod = function parentMethod() {};
function Child() {}
Child.prototype = Object.create(Parent.prototype); // Child のプロトタイプを Parent のプロトタイプで再定義
Child.prototype.constructor = Child; // Child の元のコンストラクターを復帰
しかし、いつこの最後の行を実行する必要があるのでしょうか。残念ながら、正しい答えは、場合によるということです。
元のコンストラクターを再割り当てすることが重要である場合と、これがコードの未使用の一行になる場合を定義してみましょう。
以下の場合を見てみてください。オブジェクトが自分自身を生成するために create メソッドを持っています。
function Parent() {};
function CreatedConstructor() {}
CreatedConstructor.prototype = Object.create(Parent.prototype);
CreatedConstructor.prototype.create = function create() {
return new this.constructor();
}
new CreatedConstructor().create().create(); // TypeError undefined is not a function since constructor === Parent
上記の例では、コンストラクターが Parent にリンクしているため、例外が発生します。
これを防ぐには、利用したいことに必要なコンストラクターを割り当てるだけです。
function Parent() {};
function CreatedConstructor() {}
CreatedConstructor.prototype = Object.create(Parent.prototype);
CreatedConstructor.prototype.constructor = CreatedConstructor; // set right constructor for further using
CreatedConstructor.prototype.create = function create() {
return new this.constructor();
}
new CreatedConstructor().create().create(); // it's pretty fine
これで、コンストラクターの変更が有用である理由が明確になりました。
もう一つの例を考えてみましょう。
function ParentWithStatic() {}
ParentWithStatic.startPosition = { x: 0, y:0 };
ParentWithStatic.getStartPosition = function getStartPosition() {
return this.startPosition;
}
function Child(x, y) {
this.position = {
x: x,
y: y
};
}
Child.prototype = Object.create(ParentWithStatic.prototype);
Child.prototype.constructor = Child;
Child.prototype.getOffsetByInitialPosition = function getOffsetByInitialPosition() {
var position = this.position;
var startPosition = this.constructor.getStartPosition(); // error undefined is not a function, since the constructor is Child
return {
offsetX: startPosition.x - position.x,
offsetY: startPosition.y - position.y
}
};
この例では、正しく動作を続けるために、親のコンストラクターを残す必要があります。
まとめ: コンストラクターを手動で更新したり設定したりすると、異なる結果や混乱する結果を導くことがあります。これを防ぐためには、それぞれの場合に応じてコンストラクターの役割を定義することが必要です。多くの場合、コンストラクター使用されず、再割り当ての必要はありません。
仕様書
ブラウザーの対応
| デスクトップ | モバイル | サーバー | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
constructor | Chrome 完全対応 1 | Edge 完全対応 12 | Firefox 完全対応 1 | IE 完全対応 4 | Opera 完全対応 あり | Safari 完全対応 あり | WebView Android 完全対応 1 | Chrome Android 完全対応 18 | Firefox Android 完全対応 4 | Opera Android 完全対応 あり | Safari iOS 完全対応 あり | Samsung Internet Android 完全対応 1.0 | nodejs 完全対応 あり |
凡例
- 完全対応
- 完全対応