私は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
関数への参照を返すことになっていないのですか?
コンストラクター関数のみにプロトタイプがあります。 x
はコンストラクター関数であるため、x
にはプロトタイプがあります。
b
はコンストラクター関数ではありません。したがって、プロトタイプはありません。
b
(この場合はx
)を構築した関数への参照を取得したい場合は、次を使用できます。
b.constructor
関数の_.prototype
_プロパティは、関数がコンストラクターとして呼び出されたときに、新しいオブジェクトの継承を設定するためにあります。
新しいオブジェクトが作成されると、その内部の_[[Prototype]]
_プロパティが、関数の_.prototype
_プロパティが指すオブジェクトに設定されます。
オブジェクト自体は_.prototype
_プロパティを取得しません。オブジェクトとの関係は完全に内部的です。
それがb.log()
を行うために働く理由です。 JSエンジンは、b
オブジェクト自体にlog
プロパティがないことを認識すると、内部オブジェクト_[[Prototype]]
_オブジェクトでそれを検索しようとします。正常に検出されます。
明確にするために、_[[Prototype]]
_プロパティには直接アクセスできません。これは、JSエンジンによって提供される他の構造を介して間接的にのみ変更可能な内部プロパティです。
コードを検討する前に、コードの動作を理解するために必要なプロトタイプの概念を確認してください。
[[prototype]]
_はJavaScriptオブジェクトの非表示プロパティです。この非表示プロパティは_Object.prototype
_(オブジェクトリテラルによって作成された場合)へのリンクにすぎません。この_[[prototype]]
_プロパティにアクセスする標準的な方法はありません。 。[[prototype]]
_プロパティもあります。ここでは、関数の場合、この非表示プロパティは_Function.prototype
_へのリンクです。この_[[prototype]]
_プロパティにアクセスする標準的な方法もありません。[[prototype]]
_とは別に、関数オブジェクトが作成されるたびに、その中にprototype
プロパティが作成されます。これは、隠された_[[prototype]]
_プロパティとは別です。あなたのコードに来て:
var x = function func(){}
この行が実行されると、関数オブジェクトx
が2つのリンクで作成されます:
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
_を参照していると言えます。
プロトタイプに関するいくつかの事実を以下に示します。
O
がO = new func(){}
で作成される場合、O [[prototype]]は_Function.prototype
_です。O
が_O = {}
_ thenで作成された場合、O [[prototype]]は_Object.prototype
_です。O
がO = Object.create(obj)
で作成される場合、O [[prototype]]はobj
です。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: ƒ}
prototype
は関数(実際にはコンストラクター)のプロパティであるため、このクラスのオブジェクト(このプロトタイプが属するコンストラクターから作成されたもの)のプロパティ/メソッドを定義するためです。 このリンク をご覧ください