私はJavaScriptと呼ばれるこの黒い芸術に頭を悩ませようとしています-そして、私はそれについてかなり興奮していることを認めなければなりません。私は主に「easeljs」からのコード例を見てきました。そして、私は少し混乱しています。
I(と思う)prototype
変数である関数またはプロパティにclass
を使用することと、this.someProp
「インスタンス」変数(はい、JavaScriptにはクラスがないことを理解しています。)
私が見たコードは、自分のコードのテンプレートとしてdeclare
prototype
変数を使用しており、これでそれらを参照しています。
コンストラクター内:
this.name = name;
次に宣言:
Object.prototype.name;
以降、
this.name = "Freddy";
これは「new」で呼び出される関数内にあるため、この場合、理解できるように、this
は現在のオブジェクトを指します。私が困惑させているのは、プロトタイプ宣言が何をしているのか、なぜインスタンス変数に使用するのかということです。
明確化:次のコードでは、半径のプロトタイプ宣言が何を達成しているのかわかりません。
(function(){
// constructor
function MyCircle(radius){
this.radius = radius;
}
MyCircle.prototype.radius;
this.area = function(){
return 3.14*this.radius*this.radius;
};
window.MyCircle = MyCircle;
}());
プロトタイプの値には、インスタンスに直接設定されたプロパティとは異なる重要な動作があります。これを試して:
// Create a constructor
function A() {}
// Add a prototype property
A.prototype.name = "Freddy";
// Create two object instances from
// the constructor
var a = new A();
var b = new A();
// Both instances have the property
// that we created on the prototype
console.log(a.name); // Freddy
console.log(b.name); // Freddy
// Now change the property on the
// prototype
A.prototype.name = "George";
// Both instances inherit the change.
// Really they are just reading the
// same property from the prototype
// rather than their own property
console.log(a.name); // George
console.log(b.name); // George
これは、プロトタイプの継承なしでは不可能です。
hasOwnProperty
メソッドを使用して、プロパティがインスタンスプロパティかプロトタイププロパティかをテストできます。
console.log(a.hasOwnProperty("name")); // false
インスタンスはprototype
値をオーバーライドできます。
b.name = "Chris";
console.log(b.hasOwnProperty("name")); // true
console.log(a.name); // George
console.log(b.name); // Chris
そして、prototype
値に戻ります。
delete b.name;
console.log(b.hasOwnProperty("name")); // false
console.log(b.name); // George
これは、プロトタイプ継承の強力な部分です。
他のパターンでは:
function A() {
this.name = "George";
}
this.name
変数は、新しいインスタンスごとに再度宣言されます。
メソッドをプロトタイプで宣言された関数として持つことは、理にかなっています。すべてのインスタンスで関数定義が再宣言されるのではなく、すべてのインスタンスが単一の関数を共有できます。
関数ではなく変数に関しては、インスタンスが独自の値を設定しない場合、デフォルト値にプロトタイプを使用できます。
プロトタイプに保存された値は、そのプロパティのデフォルト値を提供します。
その後、そのプロパティに値を書き込むと、instanceがその新しい値を取得し、プロトタイプ上にある値を隠しますが、そのまま残されます。
これで、質問に追加したコードのコンテキストで:
MyCircle.prototype.radius;
絶対に何もしません。それは何もしません-それはreadそのプロパティを試み、そして結果を破棄します。
他の回答では、プロトタイプとインスタンスプロパティの違いについて既に説明しています。
しかし、答えに追加するために、コードスニペットを分類しましょう。
(function(){ // <------- 1
// constructor
function MyCircle(radius){ // <------- 2
this.radius = radius; // <------- 2.1
}
MyCircle.prototype.radius; // <------- 3
this.area = function(){ // <------- 4
return 3.14*this.radius*this.radius;
};
window.MyCircle = MyCircle; // <------- 5
}());
IIFE
を作成するMyCircle
という関数を宣言します(ただし、「構築」されることはないので、誤解を招く可能性があるため、おそらく大文字を削除する必要があります)radius
インスタンスプロパティが作成されますradius
関数のMyCircle
上のprototype
プロパティにアクセスしようとすると、undefined
と評価されますarea
インスタンスプロパティを作成し、それに関数式を割り当てるMyCircle
オブジェクトでwindow
インスタンスプロパティを作成し、それにMyCircle
関数を割り当てる概要:グローバルarea
オブジェクトにMyCircle
およびwindow
プロパティを作成しているようで、MyCircle
が呼び出されたとき追加のradius
プロパティを作成します。
sage:エリアは半径を初期化するMyCircleに依存しているため、エリアの前にMyCircleを呼び出す必要があります。
window.MyCircle(10);
window.area(); // evaluates to 314
プロトタイプをプロパティ(変数)のデフォルト値に使用できることに同意します。コンストラクター関数は、プロパティを宣言する必要はありません。条件付きで実行できます。
function Person( name, age ) {
this.name = name;
if ( age ) {
this.age = age;
}
}
Person.prototype.sayHello = function() {
console.log( 'My name is ' + this.name + '.' );
};
Person.prototype.sayAge = function() {
if ( this.age ) {
console.log( 'I am ' + this.age + ' yrs old!' );
} else {
console.log( 'I do not know my age!' );
}
};
Person.prototype.age = 0.7;
//-----------
var person = new Person( 'Lucy' );
console.log( 'person.name', person.name ); // Lucy
console.log( 'person.age', person.age ); // 0.7
person.sayAge(); // I am 0.7 yrs old!
Lucyのage
が条件付きで宣言および初期化される方法を参照してください。