ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript プロトタイプを理解する

JavaScript プロトタイプを理解する

高洛峰
高洛峰オリジナル
2016-11-25 15:33:59830ブラウズ

JavaScript プロトタイプは常に人々に混乱を引き起こします。それが経験豊富な専門家であれ、作者自身であれ、この概念については、私たちが初めてプロトタイプに接した時点ですでに生じていると思います。多くの場合、new およびコンストラクター、特に関数のプロトタイプ プロパティに関連します。実際、プロトタイプは非常に単純な概念です。これをよりよく理解するには、まず、コンストラクター プロトタイプについて学んだことを忘れるという原則を思い出す必要があります。

プロトタイプとは何ですか?

プロトタイプは、他のオブジェクトがプロパティの継承を実装できるオブジェクトです。

どんなオブジェクトでもプロトタイプになることができますか?



どのオブジェクトにプロトタイプがあるか

すべてのオブジェクトにはデフォルトでプロトタイプがあります。プロトタイプ自体もオブジェクトであるため、各プロトタイプ自体もプロトタイプを持ちます (1 つの例外を除き、デフォルトのオブジェクト プロトタイプはプロトタイプの先頭です)プロトタイプ チェーンの詳細については、後で説明します)

さて、もう一度戻りましょう。オブジェクトとは何ですか?
JavaScript では、オブジェクトは、順序付けされていないキーと値のペアのコレクションです。プライマリデータ型 (未定義、null、ブール、数値、または文字列) の場合、それはオブジェクトです

すべてのオブジェクトにはプロトタイプがあると言いましたが、それを ({}).prototype として書くと、null が返されます。あなたは正しいですか?

プロトタイプのプロパティについて学んだことはすべて忘れてください。それがプロトタイプに関する混乱の原因である可能性があります。オブジェクトの真のプロトタイプは、オブジェクト内の [[Prototype]] プロパティによって保持されます。 ECMA は、標準のオブジェクト プロトタイプ アクセサー Object.getPrototype(object) を導入しました。これまでのところ、このアクセサーを実装しているのは Firefox と Chrome だけです。 IE に加えて、他のブラウザでも非標準アクセサ __proto__ がサポートされています。これらのどちらも機能しない場合は、オブジェクトのコンストラクタからそのプロトタイプ属性を見つける必要があります。次のコードは、オブジェクト プロトタイプを取得するメソッドを示しています
var a = {};

//Firefox 3.6 および Chrome 5

Object.getPrototypeOf(a) //[object Object]

//Firefox 3.6、Chrome 5 および Safari 4

a.__proto__; //[object Object]

//すべてのブラウザ

a.constructor.prototype; //[object Object]
; //[object Object]
; //[object Object]
main データ型ですが、false.__proto__ が値を返しました

main データ型のプロトタイプを取得しようとすると、強制的にオブジェクトに変換されます

//(IE でも動作しますが、偶然だけです )

false .__proto__ === Boolean( false ).__proto__; //true
継承でプロトタイプを使いたいのですが、どうすればよいでしょうか?

インスタンスのみにプロトタイプを使用することは、インスタンス オブジェクトを作成した場合、既存のオブジェクトの機能を継承することと同じです。配列と言えば、以下のようにできます (__proto__ をサポートするブラウザーの場合)
//珍しいケースで、IE では機能しません
var a = {};
a.__proto__ = Array.prototype;
a.length ; //0
————————————————————————————————————–
翻訳者注: 上記の例では、まずオブジェクト a を作成し、次に a のプロトタイプを使用して既存のオブジェクト Array の機能を継承します
—————————————————— ————————— —–

プロトタイプの本当の魅力は、複数のインスタンスが共通のプロトタイプを共有することです。プロトタイプ オブジェクト (注: つまり、オブジェクトのプロトタイプによって参照されるオブジェクト) のプロパティが定義されると、それを参照する複数のインスタンスによって継承できます (注: つまり、これらのインスタンス オブジェクトのプロトタイプは、このプロトタイプ オブジェクト)、パフォーマンスとメンテナンスの観点からこの操作の重要性は自明です

これがコンストラクターの存在理由でもありますか?

はい。コンストラクターは、インスタンスの作成時に共通のプロトタイプを提供できる便利なクロスブラウザー メカニズムを提供します

例を示す前に、constructor.prototype プロパティとは正確に何なのかを知る必要があります。

まず第一に、JavaScript はコンストラクターと他の関数を区別しないため、各関数はプロトタイプ属性を持ちます。逆に、関数でない場合、そのようなプロパティは存在しません。以下のコードを見てください

//関数はコンストラクターになることはありませんが、とにかくプロトタイプのプロパティがあります

Math.max.prototype; //[object Object]

//コンストラクターであることを意図した関数にはプロトタイプがありますも

var A = function (name) {

this .name = name;

}

A.prototype; //[object Object]
🎜//Math は関数ではないので、プロトタイプ プロパティはありません

Math.prototype; //null
これで定義を行うことができます: この関数がコンストラクターとして使用される場合、インスタンスを作成する場合。 、関数のプロトタイプ属性は、すべてのオブジェクト インスタンスにプロトタイプとして割り当てられます (注: すべてのインスタンスのプロトタイプは、関数のプロトタイプ属性を参照します)
—————————————— — —————————————————————-
翻訳者注: 次のコードでこれについて詳しく説明します

//関数 b
var b = function( ) を作成します{ var one; }
// b を使用してオブジェクト インスタンス c を作成します。 c = new b();
// b と c のコンストラクターを表示します
b.constructor; // function Function() { [ネイティブ コード] }
b.constructor==Function.constructor; //true
c.constructor; //インスタンス c のコンストラクターは b function(){ var one; }
c.constructor==b //true
// bは関数です。次のように b のプロトタイプを確認してください
b.constructor.prototype // function (){}
b.__proto__ //function (){}

//b は関数です。JavaScript が含まれていないためです。コンストラクターconstructor 関数と関数を区別するため、関数はコンストラクターと同様に
//関数のプロトタイプ (b.__proto__ または b.construtor.prototype) とは異なるプロトタイプ属性を持ちます
b.prototype //[object Object] 関数 b
のプロトタイプ属性
b.prototype==b.constructor.prototype //fasle
b.prototype==b.__proto__ //false
b.__proto__==b.constructor.prototype //true

//c は b によって作成されたオブジェクト インスタンスです。 c のプロトタイプを次のように表示します
c.constructor.prototype //[object Object] これはオブジェクトのプロトタイプです
c.__proto__ //[object Object] これはオブジェクトのプロトタイプ

c.constructor.prototype==b.constructor.prototype; //false c のプロトタイプと b のプロトタイプを比較します
c.constructor.prototype==b.prototype; //true c のプロトタイプと b のプロトタイプ属性を比較します。

//属性を追加します max
b.prototype.max = 3
//インスタンス c にも属性があります max
c.max //3
上記の例では、プロトタイプとオブジェクト インスタンス c 関数のプロトタイプ プロパティb のプロトタイプのプロパティを変更すると、オブジェクト インスタンス c
のプロトタイプも変更されます
————————————————————— ——— —————————-
関数のプロトタイプ プロパティは実際のプロトタイプとは何の関係もないことを理解することが重要です
//(例は IE では失敗します)

var A = function (name) {

this .name = name;

}

A.prototype == A.__proto__; //false

A.__proto__ == Function.prototype // true - A のプロトタイプはコンストラクターのプロトタイプ プロパティに設定されます
例をあげてください

あなたはこのような JavaScript を何百回も使用したことがあるかもしれませんが、今再びこのようなコードを見ると、異なる理解が得られるかもしれません。



//Constructor. this は新しいオブジェクトとして返され、その内部 [[prototype]] プロパティはコンストラクターのデフォルトのプロトタイプ プロパティに設定されます
var Circle = function (radius) {
this .radius = radius;
//次の行は暗黙的であり、説明のみのために追加されています
//this.__proto__ = Circle.prototype;
}
//Circle のデフォルトのプロトタイプ プロパティを拡張し、それによって生成された各インスタンスのプロトタイプを拡張します
Circle。 prototype.area = function () {
use ‐ ‐ return Math.PI* this .radius* this .radius; } // 円の 2 つのインスタンスを作成し、それぞれに共通のプロトタイプを利用します
var a = new Circle(3), b = new Circle(4);
a.area().toFixed(2) ; //28.27
b.area().toFixed(2); //50.27
コンストラクターのプロトタイプを変更すると、既に存在するそのコンストラクターのインスタンスが最新バージョンのコンストラクターを取得することになりますか?

必ずしもそうとは限りません。プロトタイプのプロパティが変更されると、そのような変更が発生します。 a.__proto__ は、 a が実際に作成された後の A.prototype への参照であるためです。

var A = function (name) {
this .name = name;
}
var a = new A( 'alpha' );
a.name; //'alpha'
A.prototype.x = 23;
a.x; //23
————————————————————————————————
訳者注: これは以下と同じです。上記例と同様に、インスタンスオブジェクトaのプロトタイプ(a.__proto__)は関数Aのプロトタイプ属性(A.prototype)への参照なので、Aのプロトタイプ属性を変更すると

この変更は、A によって作成されたオブジェクト インスタンス a に影響します。次の例では、関数 A のプロトタイプが変更されますが、A によって作成されたインスタンス a には反映されません

var A = function(name)
{
this .name = name;
}
var a = new A('alpha');
a.name; //'alpha'

A.__proto__.max = 19880716;

a.max //unknown

— —————————————————————————————————

しかし、ここで A のプロトタイプ プロパティを新しいオブジェクトに置き換えると、インスタンス オブジェクトのプロトタイプ a.__proto__ は、作成時の A の元のプロトタイプ属性を引き続き参照します

var A = function (name) {
this .name = name;
}
var a = new A( 'alpha ' );
a.name; //'alpha'
A.prototype = {x:23} //null
—————————————————— — —————————————————
訳者注: つまり、関数のプロトタイプ属性が指すオブジェクトがインスタンス作成後に変更された場合、そのオブジェクトが指すオブジェクトが関数のprototype属性で指定されたオブジェクトはインスタンス作成時に変更されます

ただし、既に作成されているインスタンスのプロトタイプには影響しません。
——————————————————————————————————————-

デフォルトのプロトタイプはどのようなものですか?

var A = function () {};
A.prototype.constructor == A; //true
var a = new A();
a.constructor == A; //true (a のコンストラクター プロパティプロトタイプです)
インスタンスとプロトタイプの関係は何ですか

a のプロトタイプが A のプロトタイプチェーンに属している場合、式 a インスタンスの値は true です。これは、 のインスタンスにトリックをかけて、それが機能しないようにできることを意味します
var A = function () {}

var a = new A();

a.__proto__ == A.prototype; // true - したがって、instanceof A は true を返します

ainstanceof A //true;

//a のプロトタイプをいじります
a.__proto__ = Function.prototype;

//a のプロトタイプは、同じプロトタイプ チェーンに存在しなくなりました。 A のプロトタイプ プロパティ

a instanceof A; //false
プロトタイプを使用して他に何ができますか?

前述したすべてのコンストラクターにはプロトタイプ プロパティがあり、それが作成するすべてのコンストラクターで使用されることを思い出してください。 インスタンスはプロトタイプを提供します。これは、元のコンストラクター Function、String などにも当てはまります。この属性を拡張することで、指定されたコンストラクターのすべてのインスタンスを拡張できます。私はこれまでの多くの記事でこの手法を使用して、関数の拡張を説明しました。トレーサー ユーティリティの記事内のすべての文字列インスタンスは、指定された回数だけ文字列自体をコピーする times メソッドを実装しています
String.prototype.times = function (count) {
Return count < '' : new Array(count ? + 1).join( this );
}

"こんにちは!" .times(3); //"こんにちは!こんにちは!こんにちは!";

"お願いします..." // 「お願い...お願い...お願い...お願い...お願い...お願い...」
プロトタイプを介して継承がどのように機能するかを教えてください。プロトタイプチェーンとは何ですか?

すべてのオブジェクトとプロトタイプにはプロトタイプがあります (注: プロトタイプもオブジェクトです)。オブジェクトのプロトタイプはオブジェクトの親を指し、親のプロトタイプは親を指します。これをプロトタイプに渡します。層ごとに接続された関係がプロトタイプ チェーンを形成します。このチェーンの最後は常にデフォルトのオブジェクト プロトタイプになります。

a.__proto__ = b;

b.__proto__ = c;

c.__proto__ = {}; //デフォルトオブジェクト

{}.__proto__.__proto__; //プロトタイプ継承メカニズムは内部で発生しますオブジェクト a の属性 foo の値を取得したい場合、JavaScript はプロトタイプ チェーン内で foo の存在を検索し、見つかった場合は foo の値を返します。それ以外の場合は、unknown が返されます。 。

課題についてはどうですか?

プロトタイプの継承はプレーヤーではありません。属性値が a.foo=’bar’ に設定されている場合、値 bar は a の属性 foo に直接設定されます。プロトタイプにプロパティを追加するには、プロトタイプを直接指定する必要があります。



声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。