Object.prototype.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,
function Type() {},false,
function Type() {},false,false
function Boolean() {
    [native code]
},false,true
function Type() {},false,Mon Sep 01 2014 16:03:49 GMT+0600
function Type() {},false,Error
function Type() {},false,function anonymous() {

}
function Type() {},false,function () {}
function Type() {},false,[object Math]
function Type() {},false,0
function Number() {
    [native code]
},false,1
function Type() {},false,[object Object]
function Type() {},false,[object Object]
function Type() {},false,/(?:)/
function Type() {},false,/(?:)/
function Type() {},false,
function String() {
    [native code]
},false,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(); // error 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
  }
};

この例では、正しく動作を続けるために、親のコンストラクターを残す必要があります。

まとめ: コンストラクターを手動で設定したり更新したりすると、異なる結果や混乱する結果を導くことがあります。これを防ぐためには、それぞれの場合に応じてコンストラクターの役割を定義することが必要です。多くの場合、コンストラクター使用されず、再割り当ての必要はありません。

仕様書

仕様書 状態 備考
ECMAScript 1st Edition (ECMA-262) 標準 初回定義。JavaScript 1.1 で実装。
ECMAScript 5.1 (ECMA-262)
Object.prototype.constructor の定義
標準  
ECMAScript 2015 (6th Edition, ECMA-262)
Object.prototype.constructor の定義
標準  
ECMAScript Latest Draft (ECMA-262)
Object.prototype.constructor の定義
ドラフト  

ブラウザーの対応

機能ChromeEdgeFirefoxInternet ExplorerOperaSafari
基本対応 あり あり1 あり あり あり
機能Android webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
基本対応 あり あり あり4 あり あり あり

ドキュメントのタグと貢献者

このページの貢献者: mfuji09, Marsf, teoli, ethertank, Yuichirou, Potappo
最終更新者: mfuji09,