プロトタイプを理解する作成するすべての関数にはプロトタイプ プロパティがあります。これは、特定の型のすべてのインスタンスで共有できるプロパティとメソッドを格納することを目的としたオブジェクトへのポインターです。次の例を考えてみましょう。 関数Person(){ } Person.prototype.name = 'ccc' 人物.プロトタイプ.年齢 = 18 Person.prototype.sayName = 関数 (){ コンソールにログ出力します。 } var person1 = 新しいPerson() person1.sayName() // --> ccc var person2 = 新しいPerson() person2.sayName() // --> ccc console.log(person1.sayName === person2.sayName) // --> true プロトタイプオブジェクトを理解する上記のコードによれば、次の図がわかります。 次の 3 つの点を理解する必要があります。
注: person1 インスタンスと person2 インスタンスとコンストラクターの間には直接的な関係はありません。 前述したように、[[prototype]] はすべての実装でアクセスできるわけではないので、インスタンスとプロトタイプ オブジェクトの間に関係があるかどうかをどのように確認すればよいでしょうか。ここで判断する方法は 2 つあります。
インスタンスプロパティとプロトタイププロパティの関係先ほど、プロトタイプには最初はコンストラクター プロパティのみが含まれており、これも共有されるため、オブジェクト インスタンスを通じてアクセスできることを説明しました。オブジェクトインスタンスを介してプロトタイプに格納された値にアクセスすることはできますが、オブジェクトインスタンスを介してプロトタイプ内の値を上書きすることはできません。インスタンスにプロパティを追加し、そのプロパティの名前がインスタンス プロトタイプのプロパティと同じである場合、そのプロパティはインスタンス上に作成され、プロトタイプのプロパティはマスクされます。次のように: 関数 Person() {} Person.prototype.name = "ccc"; Person.prototype.age = 18; Person.prototype.sayName = function() { コンソールにログ出力します。 }; var person1 = 新しい Person(); var person2 = 新しい Person(); person1.name = 'www' // person1 に名前属性を追加します person1.sayName() // --> 'www'————'インスタンスから' person2.sayName() // --> 'ccc'————'プロトタイプから' console.log(person1.hasOwnProperty('name')) // --> true console.log(person2.hasOwnProperty('name')) // --> false delete person1.name // --> person1 に新しく追加された name 属性を削除します person1.sayName() // -->'ccc'————'from prototype' プロパティがインスタンス プロパティであるかプロトタイプ プロパティであるかをどのように判断するのでしょうか?ここで、hasOwnProperty() メソッドを使用して、プロパティがインスタンス内またはプロトタイプ内に存在するかどうかを検出できます。 (このメソッドはObjectから継承されます) 次の図は、上記の例の実装とプロトタイプの関係をさまざまな状況で詳細に分析したものです。(Personコンストラクタの関係は省略されています) よりシンプルなプロトタイプ構文前の例のように、プロパティとメソッドを追加するたびに、常に Person.prototype と入力できるとは限りません。不要な入力を減らすための、より一般的なアプローチは次のとおりです。 関数 Person(){} Person.プロトタイプ = { 名前: 'ccc', 年齢: 18歳 sayName: 関数 () { console.log(この名前) } } 上記のコードでは、Person.prototype をオブジェクトリテラルとして作成された新しいオブジェクトに設定しています。最終結果は同じですが、1 つの例外があります。コンストラクター プロパティは、もはや Person を指していません。前述したように、関数が作成されるたびにそのプロトタイプ オブジェクトが同時に作成され、このオブジェクトは自動的にコンストラクター プロパティを取得します。しかし、使用する新しい構文では、デフォルトのプロトタイプ オブジェクトは基本的に完全に書き換えられるため、コンストラクター プロパティは新しいオブジェクトのコンストラクター プロパティ (Object コンストラクターを指す) になり、Person 関数を指すことはなくなります。この時点では、instanceof 演算子は正しい結果を返すことができますが、オブジェクトの型はコンストラクターを通じて判別できなくなります。次のように: var person1 = 新しいPerson() console.log(person1 インスタンスオブオブジェクト) // --> true console.log(person1 instanceof Person) // --> true console.log(person1.constructor === Person) // --> false console.log(person1.constructor === Object) // --> true ここでは、instanceof 演算子を使用して Object と Person をテストし、やはり true を返します。コンストラクター プロパティは、Person ではなく Object と等しくなります。コンストラクターが本当に重要な場合は、次のように記述できます。 関数 Person(){} Person.プロトタイプ = { コンストラクタ: Person, // --> リセット名: 'ccc', 年齢: 18歳 sayName: 関数 () { console.log(この名前) } } しかし、これにより新たな問題が発生します。上記の方法でコンストラクター プロパティをリセットすると、[[Enumerable]] 属性が true に設定されます。デフォルトでは、ネイティブ コンストラクター プロパティは列挙可能ではありません。したがって、ECMAscript5 互換の JavaScript エンジンを使用する場合は、Object.defineProperty() を試すことができます。 関数 Person(){} Person.コンストラクタ = { 名前: 'ccc', 年齢: 18歳 sayName: 関数(){ console.log(この名前) } } // コンストラクターをリセットします。ECMAscript5 互換ブラウザーにのみ適用されます。Object.defineProperty(Person.constructor, "constructor", { 列挙可能: false、 値: 人 }) プロトタイプのダイナミクスプロトタイプ内の値を検索するプロセスは単一の検索であるため、プロトタイプ オブジェクトに加えた変更はインスタンスにすぐに反映されます。例えば: 関数 Person(){} var person1 = 新しいPerson() Person.prototype.sayHi = function(){ コンソールログ('こんにちは') } person1.こんにちは() 上記のコードでは、まず Person インスタンスを作成して person1 に保存し、次に sayHi() メソッドを Person.prototype に追加します。 person1 は新しいメソッドが追加される前に作成されましたが、このメソッドに引き続きアクセスできます。その理由は、インスタンスとプロトタイプ間の接続が緩いためです。 関数 Person(){} var person1 = 新しいPerson() Person.プロトタイプ = { 名前: 'ccc', 年齢: 18歳 sayName: 関数(){ console.log(この名前) } } person1.sayName() // --> エラー 分析については次の図を参照してください。 コンストラクターが呼び出されると、元のプロトタイプへの [[prototype]] ポインターがインスタンスに追加され、プロトタイプを別のオブジェクトに変更することは、コンストラクターと元のプロトタイプ間の接続を切断することと同じです。覚えておいてください: インスタンス内のポインターはプロトタイプのみを指し、コンストラクターは指しません。 プロトタイプチェーンを理解するプロトタイプ チェーンは継承を実現するための主な方法です。基本的な考え方は、1 つの参照型に別の参照型のプロパティとメソッドを継承させることです。プロトタイプ チェーンを理解する前に、まずプロトタイプ、プロトタイプ オブジェクト、インスタンスの関係を整理する必要があります。各コンストラクターにはプロトタイプ オブジェクトがあり、プロトタイプ オブジェクトにはコンストラクターへのポインターが含まれ、インスタンスにはプロトタイプ オブジェクトへの内部ポインターが含まれます。プロトタイプ オブジェクトを別の型のインスタンスと同じにするとどうなるでしょうか?当然のことながら、このプロトタイプ オブジェクトには別のプロトタイプへのポインターが含まれます。まずコードを見て、次に画像を見てください。 関数SuperType(){ this.property = true } SuperType.prototype.getSuperValue = 関数(){ this.propertyを返す } 関数サブタイプ(){ this.subProperty = false } // スーパータイプを継承する SubType.prototype = 新しい SuperType() SubType.prototype.getSubValue = 関数 (){ this.subPropertyを返す } var インスタンス = 新しいサブタイプ() console.log(instance.getSuperValue()) // --> true 上記のコードは、SuperType と SubType の 2 つの型を定義します。各型には 1 つのプロパティと 1 つのメソッドがあります。 上の図を分析すると、インスタンスは SubType プロトタイプを指し、SubType プロトタイプは SuperType プロトタイプを指しています。 getSuperValue() メソッドはまだ SuperType.prototype にありますが、プロパティは SubType.prototype にあります。これは、property がインスタンス属性であるのに対し、getSuperValue() はプロトタイプ メソッドであるためです。 SubType.prototype は SuperType のインスタンスになったため、プロパティは当然そのインスタンス内に配置されます。また、SubType.prototype の元のコンストラクターが書き換えられたため、instance.constructor が SuperType を指すようになったことにも注意してください。 インスタンスを検索 SubType.prototypeを検索 デフォルトのプロトタイプを忘れないでくださいすべての参照型はデフォルトで Object を継承し、この継承もプロトタイプ チェーンを通じて実装されることを知っておく必要があります。すべての関数のデフォルトのプロトタイプは Object のインスタンスであるため、デフォルトのプロトタイプには Object.prototype を指す内部ポインターが含まれます。そのため、すべてのカスタム型には toString() メソッドと valueOf() メソッドがあります。したがって、完全なプロトタイプ チェーンは次のようになります。 詳細図: つまり、SubType は SuperType を継承し、SuperType は Object を継承します。 Instant.toString() を呼び出す場合、実際に呼び出されるメソッドは Object.prototype に格納されているメソッドです。 プロトタイプとインスタンスの関係を決定するプロトタイプ チェーンが非常に長い場合、プロトタイプとインスタンスの関係を決定する方法は 2 つあります。 instanceof 演算子を使用します。この演算子を使用してインスタンスとプロトタイプ チェーンに表示されるコンストラクターをテストする限り、結果は true を返します。 console.log(instance instanceof Object) // --> true console.log(インスタンスインスタンスのSuperType) // --> true console.log(インスタンス instanceof SubType) // --> true Instantof 判定メソッドに似た isPrototypeOf() メソッドを使用します。プロトタイプがプロトタイプ チェーンに出現する限り、true を返します。 console.log(Object.prototype.isPrototypeOf(instance)) // --> true console.log(SuperType.prototype.isPrototypeOf(instance)) // --> true console.log(SubType.prototype.isPrototypeOf(instance)) // --> true 方法を慎重に定義するサブタイプでは、スーパータイプのメソッドをオーバーライドしたり、スーパータイプに存在しないメソッドを追加したりする必要がある場合があります。ただし、いずれの場合でも、プロトタイプにメソッドを追加するコードは、プロトタイプを置き換えるステートメントの後に配置する必要があります。次のように: 関数SuperType(){ this.property は true です。 } SuperType.prototype.getSuperValue = 関数(){ this.propertyを返す } 関数サブタイプ(){ this.subProperty = false; } // スーパータイプを継承する SubType.prototype = 新しい SuperType() // 新しいメソッドを追加します SubType.prototype.getSubValue = function(){ this.subPropertyを返す } // スーパータイプのメソッドをオーバーライドします SubType.prototype.getSuperValue = function(){ 偽を返す } var インスタンス = 新しいサブタイプ() console.log(instance.getSuperValue()) // --> false var インスタンスSuper = 新しいスーパータイプ() console.log(instanceSuper.getSuperValue()) // -> true 上記のコードでは、最初のメソッド getSubValue() が SubType に追加されています。 2 番目のメソッド getSuperValue() はプロトタイプ チェーンに既に存在するメソッドですが、このメソッドをオーバーライドすると元のメソッドがマスクされます。つまり、SubType のインスタンスを介して getSuperValue() が呼び出されると、再定義されたメソッドが呼び出されますが、SuperType のインスタンスを介して getSuperValue() が呼び出されると、元のメソッドが引き続き呼び出されます。もう 1 つのポイントは、継承がプロトタイプ チェーンを通じて実装されている場合、プロトタイプ チェーンが書き換えられ、プロトタイプ チェーンが切断されるため、オブジェクト変数を使用してプロトタイプ メソッドを作成することはできないということです。 プロトタイプチェーンの問題継承がプロトタイプを通じて実装されると、プロトタイプは実際には別の型のインスタンスになるため、元のインスタンスのプロパティが現在のプロトタイプのプロパティになり、プロパティが共有されるようになります。次のコードを見てください。 関数SuperType(){ this.colors = ['白', '青'] } 関数サブタイプ(){ } // スーパータイプを継承する SubType.prototype = 新しい SuperType() var インスタンス1 = 新しいサブタイプ() インスタンス1.colors.push('赤') var インスタンス2 = 新しいサブタイプ() console.log(instance1.colors) // -->["白", "青", "赤"] console.log(instance2.colors) // -->["白", "青", "赤"] サブタイプのインスタンスを作成する場合、スーパータイプのコンストラクターにパラメーターを渡すことはできません。実際、すべてのオブジェクト インスタンスに影響を与えずに、スーパータイプ コンストラクターにパラメーターを渡す方法は存在しません。したがって、実際にはプロトタイプ チェーンが単独で使用されることはほとんどありません。 上記は、js のプロトタイプ、プロトタイプ オブジェクト、プロトタイプ チェーンの図の詳細な内容です。js のプロトタイプ、プロトタイプ オブジェクト、プロトタイプ チェーンの詳細については、123WORDPRESS.COM の他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
<<: Windows Server 2008 R2 リモート デスクトップのポート 3389 を変更する方法
>>: MySQL が innobackupex を使用して接続サーバーをバックアップできない場合の解決策
1|0 カーネルをコンパイルする(1)uname -rコマンドを実行してカーネルバージョンを表示しま...
主に低バージョンのブラウザ向け<!-- --> は HTML コメント タグです。上位バ...
最近、cronスケジュールタスク用のdockerを作りたいと思っており、Dockerfileで次のよ...
springmvc による Spring の統合Spring 統合 springmvc の web....
序文403 クロスオリジン エラーが発生しNo 'Access-Control-Allow-...
プロジェクトの背景最近、webpackのバージョンが古いプロジェクトがあります。 リーダー層では今の...
<iframe src="./ads_top_tian.html" all...
Docker-machineはDockerが公式に提供しているDocker管理ツールです。これは d...
目次序文1. 技術原理1.1 レイアウト1.2 コンポーネント1.3 ステータス1.4 イベント1....
目次Tomcat でプロジェクトを展開する 3 つの方法プロジェクトをwebappsディレクトリに直...
非準拠データがデータベースに入るのを防ぐために、ユーザーがデータを挿入、変更、削除、その他の操作を行...
目次共通バージョンの紹介共通バージョンのダウンロードアドレスとインストール以下に簡単な違いを示します...
現在、アプリケーション開発は基本的にフロントエンドとバックエンドに分離されています。主流のフロントエ...
前提条件gitをインストールする必要があるインストール手順1. リモートリポジトリからpyenvをク...
毎日のjQueryプラグイン - ステップ進捗軸 ステップ進捗軸ツール系のサイトでは入門チュートリア...