From 33058f2b292b3a581333bdfb21b8f671898c5060 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:40:17 -0500 Subject: initial commit --- .../global_objects/object/constructor/index.html | 257 +++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 files/ja/web/javascript/reference/global_objects/object/constructor/index.html (limited to 'files/ja/web/javascript/reference/global_objects/object/constructor') diff --git a/files/ja/web/javascript/reference/global_objects/object/constructor/index.html b/files/ja/web/javascript/reference/global_objects/object/constructor/index.html new file mode 100644 index 0000000000..eaafc2c9f9 --- /dev/null +++ b/files/ja/web/javascript/reference/global_objects/object/constructor/index.html @@ -0,0 +1,257 @@ +--- +title: Object.prototype.constructor +slug: Web/JavaScript/Reference/Global_Objects/Object/constructor +tags: + - JavaScript + - Object + - Property + - Prototype +translation_of: Web/JavaScript/Reference/Global_Objects/Object/constructor +--- +
{{JSRef}}
+ +

constructor プロパティは、インスタンスオブジェクトを生成した {{jsxref("Object")}} のコンストラクター関数への参照を返します。なお、このプロパティの値は関数そのものへの参照であり、関数名を含んだ文字列ではありません。

+ +

値が 1, true, "test" のようなプリミティブ値の場合は読み取り専用です。

+ +

解説

+ +

(Object.create(null) で生成されたオブジェクトを除いて) すべてのオブジェクトが constructor プロパティを持ちます。明示的にコンストラクター関数を用いることなく生成されたオブジェクト (オブジェクトリテラルや配列リテラルなど) は、 constructor プロパティがそのオブジェクトの基礎オブジェクトのコンストラクター型を指します。

+ +
let o = {}
+o.constructor === Object // true
+
+let o = new Object
+o.constructor === Object // true
+
+let a = []
+a.constructor === Array // true
+
+let a = new Array
+a.constructor === Array // true
+
+let n = new Number(3)
+n.constructor === Number // true
+
+ +

+ +

オブジェクトのコンストラクターの表示

+ +

以下の例では、コンストラクターである Tree と、その方のオブジェクトである theTree を生成します。そして、 theTree オブジェクトの constructor プロパティを表示します。

+ +
function Tree(name) {
+  this.name = name
+}
+
+let 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 () {}
+
+let 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 (let 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() {
+   Parent.call(this) // Make sure everything is initialized properly
+}
+Child.prototype = Object.create(Parent.prototype) // Child のプロトタイプを Parent のプロトタイプで再定義
+
+Child.prototype.constructor = Child // Child の元のコンストラクターを復帰
+ +

しかし、いつこの最後の行を実行する必要があるのでしょうか。残念ながら、正しい答えは、場合によるということです。

+ +

元のコンストラクターを再割り当てすることが重要である場合と、これがコードの未使用の一行になる場合を定義してみましょう。

+ +

以下の場合を見てみてください。オブジェクトが自分自身を生成するために create() メソッドを持っています。

+ +
function Parent() { /* ... */ }
+function CreatedConstructor() {
+   Parent.call(this)
+}
+
+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 // sets the correct constructor for future use
+
+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 } // Static member property
+ParentWithStatic.getStartPosition = function getStartPosition() {
+  return this.startPosition
+}
+
+function Child(x, y) {
+  this.position = {
+    x: x,
+    y: y
+  }
+}
+
+Child = Object.assign(ParentWithStatic)
+Child.prototype = Object.create(ParentWithStatic.prototype)
+Child.prototype.constructor = Child
+
+Child.prototype.getOffsetByInitialPosition = function getOffsetByInitialPosition() {
+  let position = this.position
+  let 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
+  }
+};
+ +

この例では、正常に動作するように親のコンストラクターを維持するか、静的プロパティを子のコンストラクタに再割り当てする必要があります。

+ +
...
+Child = Object.assign(ParentWithStatic) // Notice that we assign it before we create(...) a prototype below
+Child.prototype = Object.create(ParentWithStatic.prototype)
+...
+
+ +

または、親コンストラクターの識別子を子コンストラクター関数の別のプロパティに代入し、そのプロパティを介してアクセスします。

+ +
...
+Child.parentConstructor = ParentWithStatic
+Child.prototype = Object.create(ParentWithStatic.prototype)
+...
+   let startPosition = this.constructor.parentConstructor.getStartPosition()
+...
+
+ +
+

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

+
+ +

仕様書

+ + + + + + + + + + + + +
仕様書
{{SpecName('ESDraft', '#sec-object.prototype.constructor', 'Object.prototype.constructor')}}
+ +

ブラウザーの互換性

+ + + +

{{Compat("javascript.builtins.Object.constructor")}}

+ +

関連情報

+ + + + -- cgit v1.2.3-54-g00ecf