継承とプロトタイプチェーン継承に関しては、JavaScript にはオブジェクトという 1 つの構成要素しかありません。各インスタンス オブジェクトには、そのコンストラクターのプロトタイプ オブジェクトを指すプライベート プロパティ (proto と呼ばれる) があります。プロトタイプ オブジェクトにも独自のプロトタイプ オブジェクト (proto) があり、オブジェクトのプロトタイプ オブジェクトが null になるまでレイヤーごとに続きます。定義上、 null にはプロトタイプがなく、このプロトタイプ チェーンの最後のリンクとして機能します。 JavaScript のほぼすべてのオブジェクトは、プロトタイプ チェーンの最上位にある Object のインスタンスです。 継承されたプロパティJavaScript オブジェクトは、プロパティの動的な「バッグ」です (オブジェクト自身のプロパティを参照します)。 JavaScript オブジェクトにはプロトタイプ オブジェクトへのリンクがあります。オブジェクトのプロパティにアクセスしようとすると、一致する名前のプロパティが見つかるか、プロトタイプ チェーンの最後まで到達するまで、オブジェクトだけでなく、オブジェクトのプロトタイプ、オブジェクトのプロトタイプのプロトタイプなども検索されます。 コードサンプル 関数fn() { 1 を返します。 2 を 0 にします。 } 定数o = 新しいfn(); fn.prototype.b = 3; プロトタイプは 4 です。 コンソールにログ出力します。 コンソールにログ出力します。 コンソールにログ出力します。 コンソールにログ出力します。 // 1 // 2 // 4 // 未定義
oコンストラクタの出力を見てください { 1: 1 2 倍 __proto__: 3 です 4 文字 コンストラクタ: ƒ fn() __proto__: コンストラクタ: ƒ Object() hasOwnProperty: ƒ hasOwnProperty() isPrototypeOf: ƒ isPrototypeOf() propertyIsEnumerable: ƒ propertyIsEnumerable() toLocaleString: ƒ toLocaleString() toString: ƒtoString() 値: ƒ valueOf() __defineGetter__: ƒ __defineGetter__() __defineSetter__: ƒ __defineSetter__() __lookupGetter__: ƒ __lookupGetter__() __lookupSetter__: ƒ __lookupSetter__() __proto__ を取得する: ƒ __proto__() __proto__ を設定する: ƒ __proto__() } 継承されたメソッドJavaScript には、他のクラスベースの言語で定義されている「メソッド」はありません。 JavaScript では、任意の関数をオブジェクトのプロパティとしてオブジェクトに追加できます。関数の継承は、前述の「プロパティ シャドウイング」(他の言語でのメソッドのオーバーライドに相当) を含む他のプロパティの継承と変わりません。 継承された関数が呼び出されると、継承された関数が配置されているプロトタイプ オブジェクトではなく、現在の継承されたオブジェクトが参照されます。 var o = { a: 2、 m: 関数 () { this.a + 1 を返します。 }, }; コンソール.log(om()); // 3 // om を呼び出す場合、'this' は o を参照します。 var p = Object.create(o); // p は o から継承したオブジェクトです pa = 4; // p 独自の属性 'a' を作成します コンソールログ(pm()); // 5 // pmを呼び出すとき、'this'はpを指します // そして、p は o の m 関数を継承しているので、 // したがって、「this.a」、つまり pa は p 自身の属性「a」です JavaScript でのプロトタイプの使用JavaScript では、関数にプロパティを持たせることができます。すべての関数にはプロトタイプと呼ばれる特別なプロパティがあります。デフォルトでは、Objectのプロトタイプオブジェクトです。 関数doSomething() {} コンソールにログ出力します。 // 関数の宣言方法とは関係ありません。 // JavaScript の関数には常にデフォルトのプロトタイプ プロパティがあります。 var doSomething = function() {}; コンソールにログ出力します。 コンソールに表示される JavaScript コード ブロックには、doSomething 関数のデフォルトのプロパティ プロトタイプが表示されます。このコードを実行すると、コンソールに次のような結果が表示されます。 { コンストラクタ: ƒ doSomething(), __proto__: { コンストラクタ: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), 値: ƒ valueOf() } } 次のように、doSomething 関数のプロトタイプ オブジェクトに新しいプロパティを追加できます。 関数doSomething() {} doSomething.prototype.foo = "bar"; コンソールにログ出力します。 実行後の結果は次のように確認できます。 { foo: "バー", コンストラクタ: ƒ doSomething(), __proto__: { コンストラクタ: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), 値: ƒ valueOf() } } これで、 new 演算子を使用して、このプロトタイプ オブジェクトに基づいて doSomething のインスタンスを作成できます。 コード: 関数doSomething() {} doSomething.prototype.foo = "bar"; // プロトタイプにプロパティを追加する var doSomeInstancing = new doSomething(); doSomeInstancing.prop = "some value"; // オブジェクトにプロパティを追加します console.log(インスタンス化を実行します); 実行結果は次のステートメントのようになります。 { プロパティ: "何らかの値"、 __proto__: { foo: "バー", コンストラクタ: ƒ doSomething(), __proto__: { コンストラクタ: ƒ Object(), hasOwnProperty: ƒ hasOwnProperty(), isPrototypeOf: ƒ isPrototypeOf(), propertyIsEnumerable: ƒ propertyIsEnumerable(), toLocaleString: ƒ toLocaleString(), toString: ƒ toString(), 値: ƒ valueOf() } } } propはdoSomeInstancing自体のプロパティであり、doSomeInstancingのprotoはdoSomething.prototypeであることがわかります。 内部のプロパティを印刷します console.log("doSomeInstancing.prop: " + doSomeInstancing.prop); console.log("doSomeInstancing.foo: " + doSomeInstancing.foo); console.log("doSomething.prop: " + doSomething.prop); console.log("doSomething.foo: " + doSomething.foo); console.log("doSomething.prototype.prop: " + doSomething.prototype.prop); console.log("doSomething.prototype.foo: " + doSomething.prototype.foo); 結果は次のとおりです。 // doSomeInstancing の独自のプロパティ、値を直接返す doSomeInstancing.prop: some value // これは doSomeInstancing 自体のプロパティではありません。プロトタイプ オブジェクトを確認し、値 doSomeInstancing.foo を直接返すこのプロパティがあることを確認します: bar // これは関数自体のプロパティでも、プロトタイプオブジェクトのプロパティでもありません。レイヤーごとに検索して最終的にプロトタイプが null であることがわかった場合、そのようなプロパティは存在しないため、undefined を返します。 doSomething.prop: 未定義 doSomething.foo: 未定義 doSomething.prototype.prop: 未定義 // doSomething のプロトタイプ オブジェクトを見つけ、foo プロパティを持っているので、値 doSomething.prototype.foo: bar を直接返します。 パフォーマンスプロトタイプ チェーン上のプロパティの検索は時間がかかり、パフォーマンスに副作用をもたらします。これは、パフォーマンスが重要な状況では重要です。さらに、存在しないプロパティにアクセスしようとすると、プロトタイプ チェーン全体が走査されます。 オブジェクトのプロパティを走査すると、プロトタイプ チェーン上の列挙可能な各プロパティが列挙されます。オブジェクトに、プロトタイプ チェーン上のプロパティではなく、オブジェクト自体が定義するプロパティがあるかどうかを確認するには、すべてのオブジェクトが Object.prototype から継承する hasOwnProperty メソッドを使用する必要があります。これを説明する具体的な例を以下に示します。 console.log(doSomeInstancing.hasOwnProperty("prop")); // 真実 console.log(doSomeInstancing.hasOwnProperty("bar")); // 間違い console.log(doSomeInstancing.hasOwnProperty("foo")); // 間違い console.log(doSomeInstancing.__proto__.hasOwnProperty("foo")); // 真実 hasOwnProperty は、プロパティを処理し、プロトタイプ チェーンを走査しない JavaScript の唯一のメソッドです。 同様のメソッドとしては、Object.keys() などがあります。 注意: プロパティが未定義かどうかをチェックすることは、そのプロパティが存在するかどうかを確認する方法ではありません。プロパティはすでに存在している可能性がありますが、その値は undefined に設定されているだけです。 付録: プロトタイプチェーンは継承を実現する主な方法ですまず継承についてお話しましょう。多くのオブジェクト指向言語は、インターフェース継承と実装継承という 2 つの継承方法をサポートしています。 |- インターフェース継承: メソッドシグネチャのみを継承する |- 実装継承: 実際のメソッドを継承する 関数にはシグネチャがないため、ECMAScript ではインターフェース継承を実装できません。実装継承のみがサポートされており、実装継承は主にプロトタイプ チェーンを通じて実現されます。 プロトタイプチェーンの基本的な考え方: プロトタイプを使用すると、ある参照型が別の参照型のプロパティとメソッドを継承できるようになります。 各コンストラクターにはプロトタイプ オブジェクトがあり、その中にはコンストラクターへのポインター (constructor) が含まれます。また、インスタンス オブジェクトにはプロトタイプ オブジェクトへの内部ポインター (__proto__) が含まれます。プロトタイプ オブジェクトを別の型のインスタンスと同じにすると、プロトタイプ オブジェクトには別のプロトタイプ (__proto__) へのポインターが含まれ、他のプロトタイプにも別のコンストラクター関数 (constructor) へのポインターが含まれます。別のプロトタイプが別のタイプのインスタンスである場合、インスタンスとプロトタイプのチェーンが形成されます。 プロトタイプチェーンの基本的な考え方(図): 要約するJs 継承とプロトタイプ チェーンに関するこの記事はこれで終わりです。Js 継承とプロトタイプ チェーンに関するより関連性の高いコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
>>: MySQL トランザクション分離レベルとロックメカニズムの問題に関する深い理解
ストレステストにログインする際には、多くの異なるユーザーが必要となり、データベースに新しいデータを追...
私の友人の多くは、127.0.0.1 と localhost の違いがわからず、問題に遭遇するかもし...
Linux LVM論理ボリューム構成プロセスの詳細な説明多くの Linux ユーザーは、オペレーティ...
この記事の例では、古典的なマインスイーパゲームを実装するためのjsの具体的なコードを参考までに共有し...
この記事では、centos7 環境でバイナリ インストール パッケージを使用して mysql5.6 ...
コンテキストの定義と目的コンテキストは、コンポーネント ツリーにプロパティを明示的に渡すことなく、コ...
1. /etc/passwdファイル内のデフォルトシェルが/sbin/nologinではないユーザー...
Linuxの基本設定 Linux環境でpython3をコンパイルしてインストールする 1. Linu...
エラー: Connection to blog0@localhost failed. [08001]...
最近、C# を使用して Web プログラムを作成していたときに、次のような問題が発生しました。 Te...
Docker Compose は、複雑なアプリケーションを定義および実行するための Docker ツ...
数学、物理学、および一部の科学技術分野で使用される特殊記号は多数あります。Unicode コードには...
成果を達成する 実装コードhtml <div id=コンテナ> いらっしゃいませ <...
0x0 はじめにまず、ハッシュアルゴリズムとは何でしょうか?メッセージやセッション項目など、一部のデ...
Syn 攻撃は、最も一般的で最も簡単に悪用される攻撃方法です。TCP プロトコルの欠陥を利用して、偽...