JavaScriptを深く理解したプロトタイプおよびプロトタイプチェーン

前に書く

プロトタイプとプロトタイプチェーンは、JavaScriptで常に重要な概念でした。これらを理解することで、事前定義された参照タイプとJavaScriptでのオブジェクト継承の実装メカニズムとの関係を理解するのに役立ちます。以下は、プロトタイプとプロトタイプチェーンの私の理解と要約です。

プロトタイプ

プロトタイプオブジェクトの理解

関数オブジェクトのプロトタイププロパティ

作成するすべての関数には、オブジェクトへのポインターであるプロトタイプ属性があります。このオブジェクトの目的は、特定のタイプのすべてのインスタンスで共有できるプロパティとメソッドを含めることです。つまり、関数によってインスタンス化されたすべてのオブジェクトの__proto__プロパティは、このオブジェクトを指します。これは、関数のすべてのインスタンス化されたオブジェクトのプロトタイプです。

function Person(){
}
// 为原型对象添加方法Person.prototype.sayName = function(){ alert(this.name);}

それらの間の関係を見てみましょう。

コンストラクタプロパティ

関数が作成され、プロトタイププロパティがプロトタイプオブジェクトを指す場合、デフォルトでは、プロトタイプオブジェクトはコンストラクタープロパティを取得します。このプロパティは、プロトタイプが配置されている関数オブジェクトへのポインターです。

前の例では、Person.prototype.constructorはPerson関数オブジェクトを指しています。

それらの間の関係図を更新しましょう。

オブジェクトの__proto__属性

コンストラクターを呼び出して新しいインスタンスを作成すると、コンストラクターのプロトタイプオブジェクトを指すポインターがインスタンス内に含まれます。このポインターは、ECMA-262の第5版では[[Prototype]]と呼ばれています。すべてのオブジェクトには[[Prototype]]属性が含まれ、プロトタイプオブジェクトを指します。これは、プロトタイプチェーンを理解する上で重要な概念です。

スクリプトの[[Prototype]]プロパティにアクセスする標準的な方法はありませんが、Firefox、Safari、およびChromeの各オブジェクトはアクセスするプロパティ__proto__をサポートしています。プロトタイププロパティを区別するために、以下を使用します。 __proto__で表現します。

前のPersonコンストラクターによると、新しいインスタンスを作成します

var student = new Person();

console.log(student.__proto__ === Person.prototype); // true

上記からわかるように、この接続はインスタンスとコンストラクターの間にではなく、インスタンスとコンストラクターのプロトタイプオブジェクトの間に存在します。

これらのオブジェクト間の関係を見てみましょう

isPrototypeOf()

スクリプトの[[Prototype]]プロパティにアクセスする方法はありませんが、isPrototypeOfメソッドを使用して、オブジェクト間にこの関係が存在するかどうかを確認できます。

isPrototypeOf()メソッドは、オブジェクトが別のオブジェクトのプロトタイプチェーンに存在するかどうかをテストするために使用されます。

console.log(Person.prototype.isPrototypeOf(student)); // true

Object.getPrototypeOf()

Object.getPrototypeOf()という新しいメソッドがECMAScript 5に追加されました。このメソッドは、[[Prototype]]の値を次のように返すことができます

console.log(Object.getPrototypeOf(student) === Person.prototype); // true

プロトタイプ属性

属性アクセス

コードがオブジェクトの属性を読み取るときは常に、最初にオブジェクト自体の属性を検索し、属性が見つかった場合は属性の値を返します。見つからない場合は、オブジェクトに対応するプロトタイプオブジェクトの検索を続けます。 。

この検索プロセスのため、インスタンスに属性を追加すると、この属性はプロトタイプオブジェクトに保存された同じ名前の属性をシールドします。これは、インスタンスで属性を検索した後、後方検索を行わないためです。

属性判断

属性はインスタンス自体またはそのプロトタイプオブジェクトのいずれかである可能性があるため、どのように判断するのでしょうか。

プロパティが存在を確認する場合、hasOwnProperty()メソッドを使用して、インスタンスまたはプロトタイプにプロパティが存在するかどうかを判断できます。このメソッドは、指定された属性がインスタンスに存在する場合にのみtrueを返すことに注意してください。

function Person() {};
Person.prototype.name = "laker" ;
var student = new Person();
console.log(student.name); // lakerconsole.log(student.hasOwnProperty("name")); // false

student.name = "xiaoming";console.log(student.name); //xiaoming 屏蔽了原型对象中的 name 属性console.log(student.hasOwnProperty("name")); // true

上記は主に属性が存在することが確認された場合であり、必ずしも存在しない場合の判断は正確ではないため、属性の有無を判断してから上記の判断を行う必要があります。

属性が存在するかどうかを判断するには、属性がインスタンスまたはプロトタイプに存在するかどうかに関係なく、オブジェクトが特定の属性にアクセスできる場合にtrueを返すin演算子を使用できます。

したがって、このような関数をカプセル化して、プロトタイプにプロパティが存在するかどうかを判断できます。

function hasPrototypeProperty(object, name){ return !object.hasOwnProperty(name) && (name in object);}

for-inループ

for-inループを使用すると、インスタンスに存在する属性やプロトタイプに存在する属性など、オブジェクトを介してアクセスできる列挙可能なすべての属性が返されます。

注意すべきことの1つは、インスタンス内の列挙不可能な属性をマスクするインスタンス属性もfor-inループで返されることです。

すべての属性を取得する

オブジェクトの列挙可能なすべてのインスタンスプロパティを取得する場合は、Object.keys()メソッドを使用できます。このメソッドは、オブジェクトをパラメータとして受け取り、列挙可能なすべてのプロパティを含む文字列配列を返します。

列挙できるかどうかに関係なく、すべてのインスタンスプロパティを取得する場合は、Object.getOwnPropertyNames()メソッドを使用できます。

試作チェーン

プロトタイプチェーンを理解する

プロトタイプチェーンの概念はECMAScriptで記述されており、プロトタイプチェーンは継承を実現するための主要なメソッドとして使用されます。基本的な考え方は、ある参照型を使用して、別の参照型のプロパティとメソッドを継承することです。

プロトタイプチェーンの主な実装方法は、コンストラクターのプロトタイプオブジェクトを別のタイプのインスタンスに等しくすることです。このときのプロトタイプオブジェクトはインスタンスであるため、別のプロトタイプへのポインターが含まれます。別のコンストラクターへのポインター。別のプロトタイプが別のタイプのインスタンスである場合、上記の関係が確立され、進行性の層がインスタンスとタイプのチェーンを形成します。これがプロトタイプチェーンの基本コンセプトです。

例を見てみましょう。

function Super(){};function Middle(){};function Sub(){};Middle.prototype = new Super();Sub.prototype = new Middle();var suber = new Sub();

これらのオブジェクト間の関係を見てみましょう

デフォルトのプロトタイプ

実際、上記のプロトタイプチェーンは不完全です。すべての参照型がObjectを継承すると言ったことを覚えていますか?この継承は、プロトタイプチェーンを通じて実現されます。すべての関数のデフォルトのプロトタイプはObjectのインスタンスであることを覚えておく必要があるため、デフォルトのプロトタイプにはObject.Prototypeへの内部ポインターが含まれます。これが、すべてのカスタム型がtoString()やvalueOf()などのデフォルトのメソッドを継承する根本的な理由です。

次に、プロトタイプチェーンを更新します。

Object.prototypeはプロトタイプチェーンの終わりです。Object.prototype.__ proto__を印刷してみると、プロトタイプチェーンの終わりを意味するnull空のオブジェクトが返されることがわかります。

関数もオブジェクトです

実際、上記のプロトタイプチェーンはまだありません。なぜですか?JavaScriptでは関数もオブジェクトであることを知っているため、関数にはプロトタイプオブジェクトも必要です。例を通してそれらの間の関係を理解し​​ましょう。

コード例:

function Foo(who) {this.me = who;}
Foo.prototype.identify = function() {return "I am " + this.me;};
function Bar(who) {Foo.call( this, who );}
Bar.prototype = Object.create( Foo.prototype );
Bar.prototype.speak = function() {alert( "Hello, " + this.identify() + "." );};
var b1 = new Bar( "b1" );var b2 = new Bar( "b2" );
b1.speak();b2.speak();

最初に、関数プロトタイプなしの上記の例に含まれるプロトタイプチェーンの関係図を見てみましょう。

以下は、関数プロトタイプを追加した後のプロトタイプチェーンの関係図です。

最後に書く

プロトタイプとプロトタイプチェーンの知識を要約した後、JavaScript言語の理解はより深くなり、オブジェクトの作成と継承を後で理解するための基礎も築くと思います。実際、プロトタイプチェーンを理解するために、JavaScriptのいくつかの事前定義された型の動作と実装を理解するのは簡単です。

117件の元の記事を公開しました 69件の賞賛 10,000以上のビュー

おすすめ

転載: blog.csdn.net/zsd0819qwq/article/details/105378892