4

プロトタイプ言語では、オブジェクトは基本的に相互に複製できます。

したがって、コンストラクター関数があるとしましょう。

Bla = function()
{
    this.a = 1;
}

次のように、そのオブジェクトの新しいインスタンスを作成できますx = new Bla();。今、x.a1を返します。

と書くBla.prototype.b = 2と、x.b2 が返されます。しかし、なぜでしょうか。x が Bla を「複製」した場合、 を参照せずに とだけ言っても、同じ機能を取得できないのはなぜですか? Bla.b = 2Bla.prototypeこれはthisキーワードと関係がありますか?

4

2 に答える 2

10

ECMAScript (JavaScript) は「プロトタイプベースの継承」をサポートしています。これは、JS では「クラス」と「インスタンス」の区別がないことを意味します。他の言語の OOP とは対照的に、JS では「クラス」と「インスタンス」は基本的に同じものです。

を定義するBlaと、すぐにインスタンス化されます (すぐに使用できます) がobject Bla、同じプロパティとメソッドを持つ別のインスタンスの初期 (!) 定義を複製する「プロトタイプ」としても機能します。

ECMAScript では、オブジェクトの初期定義であっても、すべてがオブジェクトです。他の OOP 言語では、定義部分に「クラス」があります。

このオブジェクトは、最初の定義のprototypeに"Bla" (クラス "Bla" と読みます) のプロトタイプを拡張し、新しいプロパティ/関数を の現在および将来のすべてのインスタンスに追加する場合に使用します。Bla

混乱している場合は、次のコード例が違いを見つけるのに役立つと思います。

// when defining "Bla", the initial definition is copied into the "prototype"
var Bla = function()
{
    this.a = 1;
}
// we can either modify the "prototype" of "Bla"
Bla.prototype.b = 2;
// or we can modify the instance of "Bla"
Bla.c = 3;

// now lets experiment with this..

var x = new Bla();  // read: "clone the prototype of 'Bla' into variable 'x'"  
console.log(x.b);     // logs "2"  -- "b" was added to the prototype, available to all instances

console.log(x.c);     // undefined   -- "c" only exists in the instance "Bla"
console.log(Bla.c);   // logs "3"  -- "Bla" is an object, just like our new instance 'x'

// also note this:
Bla.a = 1337;
var y = new Bla();
console.log(y.a);     // logs "1"  -- because the "prototype" was cloned, 
                // opposed to the current state of object "Bla"
console.log(Bla.a);   // logs "1337" 

最後の例でわかるように、オブジェクトの現在の「状態」の複製を避けるために「プロトタイプ」の概念が必要です。

このように実装しないと、クローンを作成する前に元のオブジェクト「Bla」が使用/変更された場合、現在の状態もコピーされるため、奇妙な結果になる可能性があります。それが、言語設計者がこの構造を採用した理由prototypeです。

常に覚えておいてください: 「クラス」が他の OOP 言語にあるように、「Bla」は静的な定義ではありません。


ECMAScript 仕様には、次のように記載されていprototypeます。

プロトタイプは、ECMAScript で構造、状態、および動作の継承を実装するために使用されるオブジェクトです。コンストラクターがオブジェクトを作成すると、そのオブジェクトは、プロパティ参照を解決する目的で、コンストラクターに関連付けられたプロトタイプを暗黙的に参照します。コンストラクターに関連付けられたプロトタイプは、プログラム式 constructor.prototype によって参照できます。オブジェクトのプロトタイプに追加されたプロパティは、継承によって、プロトタイプを共有するすべてのオブジェクトによって共有されます。

同じ名前の「プロトタイプ」のような一部の JS フレームワークは、この機能を多用して Javascript 組み込みオブジェクトの機能を拡張します。

たとえばarray、メソッドを使用してネイティブ オブジェクトを拡張し、forEach不足しているこの機能を JS に追加します。

Array.prototype.forEach = function each(iterator, context) {
  for (var i = 0, length = this.length >>> 0; i < length; i++) {
    if (i in this) iterator.call(context, this[i], i, this);
  }
}
于 2012-06-16T19:24:26.717 に答える
4

クラスとインスタンスの違いに関係しています。x はクラス Bla のインスタンスです。xb = 2 を設定すると、そのインスタンスのプロパティ b を追加/設定します。b のプロトタイプに b を設定すると、そのクラス (および既存の各インスタンス) のプロパティが作成されます。同時に、ここで a で行われるようにコンストラクターで設定することとの違いです。インスタンスで a が変更されると、それは...よく変更されます。b が変更された場合、プロトタイプ b は古い値で引き続き存在しますが、そのインスタンスの新しいプロパティ b が新しい値で作成されます。(これはデフォルト値にリセットするのに役立ちます)

editテキストはコードサンプルよりもはるかに明確でない場合があることに気付いたので、違いを示すことを願って完全なサンプルを追加しました

​function bla(){
    this.a= 1;
}

var x = new bla(),
    y= new bla();


bla.prototype.b= 2;
x.c = 3;

//x already exists, but b is still set
//by setting the prototype all existing instances are changed
console.log(x.b); //2
console.log(y.b); //2

//because c has been explicitly set, it only exists on instance x
console.log(x.c); //3
console.log(y.c); //undefined


x.b = 6; //at this point
//as mentioned, setting a property on an instance, only affects
//that instance
console.log(x.b); //6
console.log(y.b); //2

//but, because b is also a prototype property, it can be 'reset'
//by deleting the instance property
delete x.b; //removes the instance b
delete y.b; //on y this does nothing, because only the prototype property exists
console.log(x.b); //2 (reset to prototype)
console.log(y.b); //2

//the final difference, because a is a class bla property, and
//not of its prototype, deleting property 'a', will actually cause a remove
delete x.a;
console.log(x.a); //undefined
于 2012-06-16T19:22:01.347 に答える