web-dev-qa-db-ja.com

JavaScriptプロトタイププロパティが新しいオブジェクトで未定義なのはなぜですか?

私はJavaScriptのプロトタイプコンセプトの概念にかなり慣れていません。

次のコードを考慮してください:

_var x = function func(){
}

x.prototype.log = function() {
  console.log("1");
}

var b = new x();
_

私が理解しているように、xはそのプロトタイプなので、b.log()は1を返すはずです。しかし、プロパティ_b.prototype_が未定義なのはなぜですか?

_b.prototype_はx関数への参照を返すことになっていないのですか?

52
Pascal Paradis

コンストラクター関数のみにプロトタイプがあります。 xはコンストラクター関数であるため、xにはプロトタイプがあります。

bはコンストラクター関数ではありません。したがって、プロトタイプはありません。

b(この場合はx)を構築した関数への参照を取得したい場合は、次を使用できます。

b.constructor
69
Peter Olson

関数の_.prototype_プロパティは、関数がコンストラクターとして呼び出されたときに、新しいオブジェクトの継承を設定するためにあります。

新しいオブジェクトが作成されると、その内部の_[[Prototype]]_プロパティが、関数の_.prototype_プロパティが指すオブジェクトに設定されます。

オブジェクト自体は_.prototype_プロパティを取得しません。オブジェクトとの関係は完全に内部的です。

それがb.log()を行うために働く理由です。 JSエンジンは、bオブジェクト自体にlogプロパティがないことを認識すると、内部オブジェクト_[[Prototype]]_オブジェクトでそれを検索しようとします。正常に検出されます。

明確にするために、_[[Prototype]]_プロパティには直接アクセスできません。これは、JSエンジンによって提供される他の構造を介して間接的にのみ変更可能な内部プロパティです。

22
the system

コードを検討する前に、コードの動作を理解するために必要なプロトタイプの概念を確認してください。

  1. _[[prototype]]_はJavaScriptオブジェクトの非表示プロパティです。この非表示プロパティは_Object.prototype_(オブジェクトリテラルによって作成された場合)へのリンクにすぎません。この_[[prototype]]_プロパティにアクセスする標準的な方法はありません。 。
  2. JavaScriptの関数はオブジェクトなので、_[[prototype]]_プロパティもあります。ここでは、関数の場合、この非表示プロパティは_Function.prototype_へのリンクです。この_[[prototype]]_プロパティにアクセスする標準的な方法もありません。
  3. この隠されたリンク_[[prototype]]_とは別に、関数オブジェクトが作成されるたびに、その中にprototypeプロパティが作成されます。これは、隠された_[[prototype]]_プロパティとは別です。

あなたのコードに来て:

var x = function func(){}

この行が実行されると、関数オブジェクトxが2つのリンクで作成されます:

  • Function.prototype(アクセス不可)、
  • x.prototype(アクセス可能)。

x.prototype.log = function(){console.log( "1"); }

xは関数オブジェクトであるため、_x.prototype_にアクセスできるので、ここにlogメソッドを含めることができます。

var b = new x();

bはオブジェクトですが、関数オブジェクトではありません。その隠しリンク_[[prototype]]_がありますが、アクセスできません。したがって、_b.prototype_のようにアクセスしようとすると、結果としてundefinedが返されます。bのプロトタイプを確認する場合は、_(x.prototype).isPrototypeOf(b);_が表示されますtrue。したがって、隠しリンクは_x.prototype_を参照していると言えます。

プロトタイプに関するいくつかの事実を以下に示します。

  1. オブジェクトOO = new func(){}で作成される場合、O [[prototype]]は_Function.prototype_です。
  2. オブジェクトOが_O = {}_ thenで作成された場合、O [[prototype]]は_Object.prototype_です。
  3. オブジェクトOO = Object.create(obj)で作成される場合、O [[prototype]]はobjです。
12
Anshul

JavaScriptのすべての通常のオブジェクトには、内部プロトタイプスロットがあります(注:ここのプロトタイプは、プロトタイププロパティを参照していません)。 ECMAScript標準( http://www.ecma-international.org/ecma-262/6.0/index.html )は、このスロットが[[Prototype]]と呼ばれることを指定しています。 __proto__プロパティを介してこのスロットにアクセスできます。

__proto__は、ブラウザー間で確実に使用できるとは限りません。 __proto__はECMAScript 6の公式プロパティになります

ただし、prototypeプロパティは、構築されたオブジェクトの__proto__プロパティになるものを設定するコンストラクタ関数のプロパティです。

コアJavaScriptタイプ(日付、配列など)など、特定のタイプのプロトタイププロパティにアクセスできます。また、JavaScript関数(コンストラクターと見なすことができます)には、パブリックプロトタイププロパティがあります。ただし、関数のインスタンスにはプロトタイププロパティがありません。

あなたの場合、var b = new x();、bは関数xのインスタンスです。したがって、b.prototypeは未定義です。ただし、bには内部[[Prototype]]スロットがあります。 Googleでb.__proto__を出力する場合Chrome例、バージョン63.0.3239.132、またはバージョン43.0.4などのFirefox

console.log(b.__proto__);

[[Prototype]]スロットは次のように表示されます。

{log: ƒ, constructor: ƒ}

それでおしまい。


参考までに、コードスニペット全体を以下のように配置します。

var x = function() {
};
x.prototype.log = function() {
  console.log("1");
}

var b = new x();
b.log();  // 1

console.log(b.prototype); // undefined
console.log(b.__proto__); // {log: ƒ, constructor: ƒ}
console.log(x.prototype); // {log: ƒ, constructor: ƒ}
12
Yuci

prototypeは関数(実際にはコンストラクター)のプロパティであるため、このクラスのオブジェクト(このプロトタイプが属するコンストラクターから作成されたもの)のプロパティ/メソッドを定義するためです。 このリンク をご覧ください

1
Danilo Valente