web-dev-qa-db-ja.com

JavaScriptでの 'prototype'と 'this'の使用

違いは何ですか

var A = function () {
    this.x = function () {
        //do something
    };
};

そして

var A = function () { };
A.prototype.x = function () {
    //do something
};
752
sw234

例は非常に異なる結果をもたらします。

違いを見る前に、次の点に注意してください。

  • コンストラクタのprototypeは、インスタンスのプライベートな[[Prototype]]プロパティを介してインスタンス間でメソッドと値を共有する方法を提供します。
  • 関数のthisは、関数の呼び出し方法またはbindの使用によって設定されます(ここでは説明しません)。関数がオブジェクト上で呼び出される場合(例えばmyObj.method())、メソッド内のthisはそのオブジェクトを参照します。thisが呼び出しによってもbindの使用によっても設定されていない場合は、グローバルオブジェクト(ブラウザのウィンドウ)または厳密モードにデフォルト設定されます。未定義のままです。
  • JavaScriptはオブジェクト指向言語です。つまり、ほとんどの値は関数を含むオブジェクトです。 (文字列、数字、およびブール値はnotオブジェクトです。)

問題のスニペットは次のとおりです。

var A = function () {
    this.x = function () {
        //do something
    };
};

この場合、変数Aには関数への参照である値が割り当てられます。その関数がA()を使用して呼び出されると、その関数のthisはグローバルオブジェクトに設定されないため、式this.xは有効なwindow.xです。その結果、右側の関数式への参照がwindow.xに割り当てられます。

の場合:

var A = function () { };
A.prototype.x = function () {
    //do something
};

非常に異なる何かが起こります。最初の行で、変数Aに関数への参照が割り当てられています。 JavaScriptでは、すべての関数オブジェクトにデフォルトでprototypeプロパティがあるため、A.prototypeオブジェクトを作成するためのコードは別にありません。

2行目のA.prototype.xに、関数への参照が割り当てられています。存在しない場合はxプロパティを作成し、存在する場合は新しい値を割り当てます。そのため、オブジェクトのxプロパティが式に含まれている最初の例との違いがわかります。

別の例は以下の通りです。それは最初のものに似ています(そしておそらくあなたが尋ねようとしていたもの):

var A = new function () {
    this.x = function () {
        //do something
    };
};

この例では、new演算子が関数式の前に追加されているため、関数はコンストラクタとして呼び出されます。 newで呼び出されると、関数のthisは、プライベートの[[Prototype]]プロパティがコンストラクタのpublicprototypeを参照するように設定されている新しいObjectを参照するように設定されます。そのため、代入文では、この新しいオブジェクトにxプロパティが作成されます。コンストラクタとして呼び出されると、関数はデフォルトでそのthisオブジェクトを返すので、別のreturn this;ステートメントは必要ありません。

Axプロパティがあることを確認するには、次のようにします。

console.log(A.x) // function () {
                 //   //do something
                 // };

コンストラクタを参照する唯一の方法はA.constructorであるため、これはnewの珍しい使い方です。もっと一般的なことです:

var A = function () {
    this.x = function () {
        //do something
    };
};
var a = new A();

同様の結果を得るためのもう1つの方法は、すぐに呼び出される関数式を使用することです。

var A = (function () {
    this.x = function () {
        //do something
    };
}());

この場合、Aは右側の関数呼び出しの戻り値を代入しています。ここでも、thisは呼び出しで設定されていないため、グローバルオブジェクトを参照し、this.xは有効なwindow.xです。関数は何も返さないので、Aundefinedの値を持ちます。

この2つのアプローチの違いは、JavaScriptオブジェクトをJSONとの間でシリアライズおよびデシリアライズする場合にも明らかになります。オブジェクトのプロトタイプで定義されたメソッドは、オブジェクトをシリアル化してもシリアル化されません。たとえば、オブジェクトのデータ部分だけをシリアル化したい場合に便利ですが、そのメソッドではありません。

var A = function () { 
    this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance)); 
// {"objectsOwnProperties":"are serialized"} 

関連する質問

サイドノート:2つの方法の間でメモリ使用量を大幅に節約することはできませんが、メソッドとプロパティを共有するためにプロトタイプを使用すると、各インスタンスよりメモリ使用量が少なくなります。独自のコピーを持っています。

JavaScriptは低レベルの言語ではありません。プロトタイピングや他の継承パターンを、メモリの割り当て方法を明示的に変更する方法として考えることは、あまり意味がありません。

450
keparo

他の人が最初のバージョンを言ったように、 "this"を使用すると、クラスAのすべてのインスタンスが関数メソッド "x"の独自の独立したコピーを持つことになります。 "prototype"を使用することは、クラスAの各インスタンスがメソッド "x"の同じコピーを使用することを意味します。

この微妙な違いを示すためのコードをいくつか示します。

// x is a method assigned to the object using "this"
var A = function () {
    this.x = function () { alert('A'); };
};
A.prototype.updateX = function( value ) {
    this.x = function() { alert( value ); }
};

var a1 = new A();
var a2 = new A();
a1.x();  // Displays 'A'
a2.x();  // Also displays 'A'
a1.updateX('Z');
a1.x();  // Displays 'Z'
a2.x();  // Still displays 'A'

// Here x is a method assigned to the object using "prototype"
var B = function () { };
B.prototype.x = function () { alert('B'); };

B.prototype.updateX = function( value ) {
    B.prototype.x = function() { alert( value ); }
}

var b1 = new B();
var b2 = new B();
b1.x();  // Displays 'B'
b2.x();  // Also displays 'B'
b1.updateX('Y');
b1.x();  // Displays 'Y'
b2.x();  // Also displays 'Y' because by using prototype we have changed it for all instances

他の人が述べたように、どちらかの方法を選択するにはさまざまな理由があります。私のサンプルは、その違いを明確に示すためのものです。

229
Benry

次の2つの例を見てください。

var A = function() { this.hey = function() { alert('from A') } };

vs.

var A = function() {}
A.prototype.hey = function() { alert('from prototype') };

ここのほとんどの人々(特にトップ評価の回答)は、なぜ説明することなく、彼らがどのように異なるかを説明しようとしました。これは間違っていると思います。最初に基本を理解すると、違いが明らかになります。最初に基礎を説明してみましょう...

a)関数はJavaScriptのオブジェクトです。 JavaScriptのすべてのオブジェクトは内部プロパティを取得します(つまり、Chromeのようなブラウザを除き、他のプロパティのようにアクセスすることはできません)。しばしば__proto__(実際にはanyObject.__proto__と入力できますChromeそれが参照するものを見るために、これはただのプロパティ、それ以上、JavaScriptのプロパティ=オブジェクト内の変数、それ以上ではありません。

では、この__proto__プロパティは何を指しているのでしょうか?まあ、通常は別のオブジェクト(理由については後で説明します)。 __proto__プロパティのJavaScriptが別のオブジェクトをポイントしないように強制する唯一の方法は、var newObj = Object.create(null)を使用することです。これを行っても、__proto__プロパティはオブジェクトのプロパティとして存在しますが、別のオブジェクトを指さないだけで、nullを指しています。

ほとんどの人が混乱する場所は次のとおりです。

JavaScriptで新しい関数を作成すると(オブジェクトでもありますが、覚えていますか?)、定義されるとすぐに、JavaScriptはprototypeという関数に新しいプロパティを自動的に作成します。それを試してみてください:

var A = [];
A.prototype // undefined
A = function() {}
A.prototype // {} // got created when function() {} was defined

A.prototypeは、__proto__プロパティとは完全に異なります。この例では、「A」には「prototype」および__proto__という2つのプロパティがあります。これは人々にとって大きな混乱です。 prototypeおよび__proto__プロパティはまったく関係がなく、別々の値を指す別々のものです。

あなたは不思議に思うかもしれません:なぜJavaScriptにはすべてのオブジェクトに__proto__プロパティが作成されているのですか? 1つの単語:delegation。オブジェクトのプロパティを呼び出したときに、そのオブジェクトにオブジェクトがない場合、JavaScriptは__proto__によって参照されるオブジェクトを探して、おそらくそれを持っているかどうかを確認します。持っていない場合、チェーンが終了するまで、そのオブジェクトの__proto__プロパティなどを調べます。したがって、名前プロトタイプチェーン。もちろん、__proto__がオブジェクトをポイントせず、代わりにnullをポイントしている場合、幸運なことに、JavaScriptはそれを認識し、プロパティのundefinedを返します。

また、関数を定義するときに、JavaScriptが関数のprototypeというプロパティを作成するのはなぜだろうと思うかもしれません。それはあなたをだまそうとするので、はいあなたをだますクラスベースの言語のように動作すること.

例に進み、Aから「オブジェクト」を作成しましょう。

var a1 = new A();

このことが起こったとき、バックグラウンドで何かが起こっています。 a1は、新しい空のオブジェクトが割り当てられた通常の変数です。

関数呼び出しA()の前に演算子newを使用したという事実は、バックグラウンドで追加の処理を行いました。 newキーワードにより、a1を参照する新しいオブジェクトが作成されましたが、そのオブジェクトは空です。さらに、次のことが発生します。

各関数定義には、prototype__proto__プロパティとは異なり、アクセスできる)と呼ばれる新しいプロパティが作成されると言いました。さて、そのプロパティは現在使用されています。

これで、焼きたての空のa1オブジェクトができました。 JavaScriptのすべてのオブジェクトには、nullであろうと別のオブジェクトであろうと、何かを指す内部__proto__プロパティがあります(a1にもあります)。 new演算子は、その__proto__プロパティを設定して、関数のprototypeプロパティを指すようにします。もう一度読んでください。基本的にこれです:

a1.__proto__ = A.prototype;

A.prototypeは空のオブジェクトにすぎないと言いました(a1を定義する前に別のオブジェクトに変更しない限り)。そのため、基本的にa1.__proto__は同じものを指しますA.prototypeが指すものは、その空のオブジェクトです。これらは両方とも、この行が発生したときに作成された同じオブジェクトを指します。

A = function() {} // JS: cool. let's also create A.prototype pointing to empty {}

var a1 = new A()ステートメントが処理されると、別のことが起こります。基本的にA()が実行され、Aが次のような場合:

var A = function() { this.hey = function() { alert('from A') } };

function() { }内のすべてのものが実行されます。 this.hey..行に到達すると、thisa1に変更され、次のようになります。

a1.hey = function() { alert('from A') }

thisa1に変更される理由については説明しませんが、詳細については これは素晴らしい答えです です。

要約すると、var a1 = new A()を実行すると、バックグラウンドで3つのことが発生します。

  1. まったく新しい空のオブジェクトが作成され、a1に割り当てられます。 a1 = {}
  2. a1.__proto__プロパティは、A.prototypeが指す(別の空のオブジェクト{})と同じものを指すように割り当てられます

  3. 関数A()は、ステップ1で作成された新しい空のオブジェクトにthisを設定して実行されます(thisa1に変わる理由について上記で参照した回答を読んでください)

次に、別のオブジェクトを作成してみましょう。

var a2 = new A();

手順1、2、3が繰り返されます。何か気づきましたか?キーワードはrepeat。ステップ1:a2は新しい空のオブジェクト、ステップ2:その__proto__プロパティは同じことを指しますA.prototypeが指し、最も重要なのは、ステップ3:関数A()が再び実行されることです。つまり、a2は関数を含むheyプロパティを取得します。 a1およびa2には、heyという名前の2つのSEPARATEプロパティがあり、2つのSEPARATE関数を指します。同じことをしている同じ2つの異なるオブジェクトに重複した関数があります...おっと... new Aで作成された1000個のオブジェクトがある場合、すべての関数宣言が何かよりも多くのメモリを消費した後、これのメモリの意味を想像できます番号2です。これをどのように防ぐのでしょうか。

__proto__プロパティがすべてのオブジェクトに存在する理由を覚えていますか? a1(存在しない)でyoManプロパティを取得する場合、その__proto__プロパティが参照され、オブジェクトである場合(そしてほとんどの場合そうです) 、yoManが含まれているかどうかをチェックし、含まれていない場合は、そのオブジェクトの__proto__などを調べます。含まれている場合、そのプロパティ値を取得して表示します。

そのため、誰かがこの事実+ a1を作成するときに、その__proto__プロパティが同じ(空の)オブジェクトA.prototypeを指し、これを行うという事実を使用することにしました。

var A = function() {}
A.prototype.hey = function() { alert('from prototype') };

クール!これで、a1を作成すると、上記の3つのステップがすべて実行されます。ステップ3では、function A()には実行するものがないため、何もしません。そして、私たちがするなら:

a1.hey

a1heyが含まれていないことがわかり、その__proto__プロパティオブジェクトが存在するかどうかを確認します。

このアプローチでは、新しいオブジェクトが作成されるたびに機能が複製されるステップ3の部分を削除します。 a1a2が個別のheyプロパティを持っている代わりに、それらのどれも持っていません。今、あなたは自分自身を理解していると思います。それは素晴らしいことです...__proto__Function.prototypeを理解すれば、これらのような質問はかなり明白になります。

注:一部の人々は、内部プロトタイププロパティを__proto__として呼び出さない傾向があります。この名前を投稿で使用して、2つの異なるものとしてFunctional.prototypeプロパティと明確に区​​別しています。

143
daremkd

ほとんどの場合、それらは基本的に同じですが、2番目のバージョンでは、オブジェクトごとに個別の関数ではなく関数のインスタンスが1つしかないため、メモリを節約できます。

最初の形式を使用する理由は「非公開メンバー」にアクセスするためです。例えば:

var A = function () {
    var private_var = ...;

    this.x = function () {
        return private_var;
    };

    this.setX = function (new_x) {
        private_var = new_x;
    };
};

Javascriptのスコープ規則のため、private_varはthis.xに割り当てられた関数で利用できますが、オブジェクトの外側では利用できません。

57
Matthew Crumley

最初の例では、そのオブジェクトのインターフェースのみを変更しています。 2番目の例は、そのクラスのすべてのオブジェクトのインターフェースを変更します。

26
Glenn

thisの代わりにprototypeを使用することによる最終的な問題は、メソッドをオーバーライドするときに、基本クラスのコンストラクターがオーバーライドされたメソッドを参照することです。このことを考慮:

BaseClass = function() {
    var text = null;

    this.setText = function(value) {
        text = value + " BaseClass!";
    };

    this.getText = function() {
        return text;
    };

    this.setText("Hello"); // This always calls BaseClass.setText()
};

SubClass = function() {
    // setText is not overridden yet,
    // so the constructor calls the superclass' method
    BaseClass.call(this);

    // Keeping a reference to the superclass' method
    var super_setText = this.setText;
    // Overriding
    this.setText = function(value) {
        super_setText.call(this, "SubClass says: " + value);
    };
};
SubClass.prototype = new BaseClass();

var subClass = new SubClass();
console.log(subClass.getText()); // Hello BaseClass!

subClass.setText("Hello"); // setText is already overridden
console.log(subClass.getText()); // SubClass says: Hello BaseClass!

対:

BaseClass = function() {
    this.setText("Hello"); // This calls the overridden method
};

BaseClass.prototype.setText = function(value) {
    this.text = value + " BaseClass!";
};

BaseClass.prototype.getText = function() {
    return this.text;
};

SubClass = function() {
    // setText is already overridden, so this works as expected
    BaseClass.call(this);
};
SubClass.prototype = new BaseClass();

SubClass.prototype.setText = function(value) {
    BaseClass.prototype.setText.call(this, "SubClass says: " + value);
};

var subClass = new SubClass();
console.log(subClass.getText()); // SubClass says: Hello BaseClass!

これが問題ではないと考えるなら、それはあなたがプライベート変数なしで生きることができるかどうか、そしてあなたがそれを見たときにあなたがリークを知るのに十分経験しているかどうかにかかっている。また、メソッド定義の後にコンストラクタロジックを配置しなければならないのは不便です。

var A = function (param1) {
    var privateVar = null; // Private variable

    // Calling this.setPrivateVar(param1) here would be an error

    this.setPrivateVar = function (value) {
        privateVar = value;
        console.log("setPrivateVar value set to: " + value);

        // param1 is still here, possible memory leak
        console.log("setPrivateVar has param1: " + param1);
    };

    // The constructor logic starts here possibly after
    // many lines of code that define methods

    this.setPrivateVar(param1); // This is valid
};

var a = new A(0);
// setPrivateVar value set to: 0
// setPrivateVar has param1: 0

a.setPrivateVar(1);
//setPrivateVar value set to: 1
//setPrivateVar has param1: 0

対:

var A = function (param1) {
    this.setPublicVar(param1); // This is valid
};
A.prototype.setPublicVar = function (value) {
    this.publicVar = value; // No private variable
};

var a = new A(0);
a.setPublicVar(1);
console.log(a.publicVar); // 1
20
tarkabak

すべてのオブジェクトはプロトタイプオブジェクトにリンクされています。存在しないプロパティにアクセスしようとすると、JavaScriptはそのプロパティのオブジェクトのプロトタイプオブジェクトを調べ、存在する場合はそれを返します。

関数コンストラクターのprototypeプロパティは、newを使用するときにその関数で作成されたすべてのインスタンスのプロトタイプオブジェクトを参照します。


最初の例では、x関数で作成された各インスタンスにプロパティAを追加します。

var A = function () {
    this.x = function () {
        //do something
    };
};

var a = new A();    // constructor function gets executed
                    // newly created object gets an 'x' property
                    // which is a function
a.x();              // and can be called like this

2番目の例では、Aで作成されたすべてのインスタンスが指すプロトタイプオブジェクトにプロパティを追加しています。

var A = function () { };
A.prototype.x = function () {
    //do something
};

var a = new A();    // constructor function gets executed
                    // which does nothing in this example

a.x();              // you are trying to access the 'x' property of an instance of 'A'
                    // which does not exist
                    // so JavaScript looks for that property in the prototype object
                    // that was defined using the 'prototype' property of the constructor

結論として、最初の例では関数のコピーが各インスタンスに割り当てられています。 2番目の例では、関数の単一コピーがすべてのインスタンスで共有されています

19
destoryer

違いは何ですか? =>たくさん。

thisバージョンはカプセル化、つまりデータ隠蔽を可能にするために使用されると思います。プライベート変数を操作するのに役立ちます。

次の例を見てみましょう。

var AdultPerson = function() {

  var age;

  this.setAge = function(val) {
    // some Housekeeping
    age = val >= 18 && val;
  };

  this.getAge = function() {
    return age;
  };

  this.isValid = function() {
    return !!age;
  };
};

これで、prototype構造体は次のように適用できます。

異なる成人は異なる年齢を持っていますが、すべての成人が同じ権利を取得しています。
だから、これではなくプロトタイプを使って追加します。

AdultPerson.prototype.getRights = function() {
  // Should be valid
  return this.isValid() && ['Booze', 'Drive'];
};

今実装を見てみましょう。

var p1 = new AdultPerson;
p1.setAge(12); // ( age = false )
console.log(p1.getRights()); // false ( Kid alert! )
p1.setAge(19); // ( age = 19 )
console.log(p1.getRights()); // ['Booze', 'Drive'] ( Welcome AdultPerson )

var p2 = new AdultPerson;
p2.setAge(45);    
console.log(p2.getRights()); // The same getRights() method, *** not a new copy of it ***

お役に立てれば。

15
oozzal

プロトタイプはクラスのテンプレートです。これは将来のすべてのインスタンスに適用されます。これはオブジェクトの特定のインスタンスです。

13
harropriiz

私がJavaScriptトレーニングコース中に学んだより包括的な答えをあなたにあげましょう。

ほとんどの回答はすでに違いを述べています。つまり、プロトタイプを作成するときにすべての(将来の)インスタンスで共有されています。これに対して、クラスで関数を宣言すると、インスタンスごとにコピーが作成されます。

一般的には、正しいことも悪いこともありません。それは、好みに応じて、または要件に応じて設計を決定することです。プロトタイプは、この回答の最後にあると思いますが、オブジェクト指向の方法で開発するために使用される手法です。

あなたはあなたの質問に2つのパターンを示しました。もう2つ説明し、違いがあれば説明します。自由に編集/拡張してください。すべての例で、それは場所を持ちそして動くことができる車のオブジェクトについてです。

オブジェクトデコレータパターン

このパターンが今日でもまだ適切であるかどうかわからないが、それは存在する。そしてそれについて知るのは良いことです。オブジェクトとプロパティをdecorator関数に渡すだけです。デコレータはプロパティとメソッドを持つオブジェクトを返します。

var carlike = function(obj, loc) {
    obj.loc = loc;
    obj.move = function() {
        obj.loc++;
    };
    return obj;
};

var amy = carlike({}, 1);
amy.move();
var ben = carlike({}, 9);
ben.move();

機能クラス

JavaScriptの関数は特殊なオブジェクトです。呼び出されることに加えて、関数は他のオブジェクトのようにプロパティを格納することができます。

この場合Car関数 think オブジェクト)であり、慣れ親しんだ方法で呼び出すことができます。それはプロパティmethods(これはmove関数を持つオブジェクトです)を持ちます。 Carが呼び出されると、extend関数が呼び出されます。これは何らかの魔法をかけ、Car内で定義されたメソッドでmethods関数(thinkオブジェクト)を拡張します。

この例は異なりますが、質問の最初の例に最も近いものです。

var Car = function(loc) {
    var obj = {loc: loc};
    extend(obj, Car.methods);
    return obj;
};

Car.methods = {
    move : function() {
        this.loc++;
    }
};

var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

プロトタイプクラス

最初の2つのパターンは、共有メソッドを定義するための技法の使用、またはコンストラクターの本体内でインラインで定義されているメソッドの使用についての説明を可能にします。どちらの場合も、すべてのインスタンスに独自のmove関数があります。

プロトタイプの委任による機能共有がプロトタイプのパターンにとってまさに目標であるため、プロトタイプのパターンは同じ検査には向いていません。他の人が指摘したように、それはより良いメモリフットプリントを持つことが期待されています。

ただし、知っておくと便利な点が1つあります。すべてのprototypeオブジェクトには、便利なプロパティconstructorがあります。これは、付属の関数(thinkオブジェクト)を指しています。

最後の3行について

この例では、Carprototypeオブジェクトにリンクしています。このオブジェクトはconstructorを介してCar自体にリンクしています。つまり、Car.prototype.constructorCar自体です。これにより、どのコンストラクタ関数が特定のオブジェクトを構築したのかを把握できます。

amy.constructorの検索は失敗するため、コンストラクタープロパティを持つCar.prototypeに委任されます。そしてamy.constructorCarです。

さらに、amyinstanceofCarです。 instanceof演算子は、右側のオペランドのプロトタイプオブジェクト(Car)が、左側のオペランドのプロトタイプ(amy)チェーンのどこかにあるかどうかを調べることによって機能します。

var Car = function(loc) {
    var obj = Object.create(Car.prototype);
    obj.loc = loc;
    return obj;
};

Car.prototype.move = function() {
        this.loc++;
};

var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();

console.log(Car.prototype.constructor);
console.log(amy.constructor);
console.log(amy instanceof Car);

何人かの開発者は最初は混乱するかもしれません。下記の例を参照してください。

var Dog = function() {
  return {legs: 4, bark: alert};
};

var fido = Dog();
console.log(fido instanceof Dog);

instanceofプロトタイプチェーンのどこにもfalseのプロトタイプが見つからないため、Dog演算子はfidoを返します。 fidoは、オブジェクトリテラルを使用して作成された単純なオブジェクトです。つまり、単にObject.prototypeに委任します。

擬古典的パターン

これは実際にはプロトタイプ・パターンのもう1つの形式であり、単純化された形式であり、例えばJavaでプログラムを作成する人にとってはなじみのあるものです。これはnewコンストラクターを使用するためです。

それは実際に原型パターンと同じことをします、それは原型パターンの単なる構文上の糖です。

ただし、主な違いは、擬似古典的パターンを使用する場合にのみ適用されるJavaScriptエンジンで実装された最適化があることです。疑似古典的パターンは原型パターンのおそらくより速いバージョンと考えてください。両方の例のオブジェクトの関係は同じです。

var Car = function(loc) {
    this.loc = loc;
};

Car.prototype.move = function() {
        this.loc++;
};

var amy = new Car(1);
amy.move();
var ben = new Car(9);
ben.move();

最後に、オブジェクト指向プログラミングをどのように行うことができるかを理解することはそれほど難しくないはずです。 2つのセクションがあります。

プロトタイプ(チェーン)内の共通のプロパティ/メソッドを定義する1つのセクション。

そして、オブジェクトを互いに区別する定義を入れる別のセクション(例の中のloc変数)。

これが、スーパークラスやサブクラスのような概念をJavaScriptに適用することを可能にするものです。

追加または編集してください。もう一度完成すれば、これをコミュニティWikiにすることができます。

12
Ely

私はこれが死に答えられたことを知っています、しかし、私は速度差の実際の例を示したいです。

Function directly on object

Function on prototype

ここでは、Chromeでprintメソッドを使用して2,000,000個の新しいオブジェクトを作成しています。すべてのオブジェクトを配列に格納しています。プロトタイプにprintを付けると、約1/2の時間がかかります。

12
Arnav Aggarwal

@ Matthew Crumleyは正しいと思います。それらは機能的に、構造的にではないにしても同等です。 Firebugを使用してnewを使用して作成されたオブジェクトを見ると、それらが同じであることがわかります。しかし、私の好みは次のようになります。私はC#/ Javaで慣れ親しんだものにもっと似ているように思えます。つまり、クラスを定義し、フィールド、コンストラクタ、およびメソッドを定義します。

var A = function() {};
A.prototype = {
    _instance_var: 0,

    initialize: function(v) { this._instance_var = v; },

    x: function() {  alert(this._instance_var); }
};

EDIT変数のスコープが非公開であることを意味するのではなく、JavaScriptでクラスを定義する方法を説明しようとしていました。これを反映するように変数名が変更されました。

10
tvanfosson

他の回答で説明したように、プロトタイプ内の関数は、インスタンス化ごとに作成される関数ではなく、すべてのインスタンス化と共有されているため、これは実際にはパフォーマンス上の考慮事項です。

これを示すためにjsperfをまとめました。クラスのインスタンス化にかかる時間には劇的な違いがありますが、実際には多くのインスタンスを作成している場合にのみ意味があります。

http://jsperf.com/functions-in-constructor-vs-prototype

9
Devgr

静的型付け言語について考えてみましょう。prototypeのことは静的で、thisのことはインスタンスに関連しています。

7
Wayou