web-dev-qa-db-ja.com

プロトタイプを使用する場合のJavaScript

Jsでプロトタイプメソッドを使用するのが適切な場合を理解したいと思います。常に使用する必要がありますか?または、それらの使用が好ましくない場合やパフォーマンスが低下する場合がありますか?

Jsのネームスペースの一般的な方法でこのサイトを検索すると、ほとんどの場合、プロトタイプではない実装を使用しているようです。つまり、オブジェクトまたは関数オブジェクトを使用して名前空間をカプセル化します。

クラスベースの言語から来たので、平行線を引こうとしないことは難しく、プロトタイプは「クラス」のようなものであり、名前空間の実装は静的メソッドのようなものだと思います。

87
opl

プロトタイプはoptimizationです。

それらを適切に使用する素晴らしい例は、jQueryライブラリーです。 $('.someClass')を使用してjQueryオブジェクトを取得するたびに、そのオブジェクトには多数の「メソッド」があります。ライブラリはオブジェクトを返すことでそれを達成できます:

return {
   show: function() { ... },
   hide: function() { ... },
   css: function() { ... },
   animate: function() { ... },
   // etc...
};

しかし、メモリ内のすべてのjQueryオブジェクトには、同じメソッドを何度も繰り返し含む数十の名前付きスロットがあることになります。

代わりに、これらのメソッドはプロトタイプで定義され、すべてのjQueryオブジェクトはそのプロトタイプを「継承」して、実行時のコストをほとんどかけずにこれらすべてのメソッドを取得します。

JQueryがどのように正しく機能するかという非常に重要な部分の1つは、これがプログラマから隠されていることです。ライブラリを使用するときに心配する必要のあるものとしてではなく、純粋に最適化として扱われます。

JavaScriptの問題は、ネイキッドコンストラクター関数では、呼び出し元がnewをプレフィックスとして付けることを忘れないでください。そうしないと、通常は機能しません。これには正当な理由はありません。 jQueryは、そのナンセンスを通常の関数$なので、オブジェクトの実装方法を気にする必要はありません。

指定したプロトタイプでオブジェクトを簡単に作成できるように、ECMAScript 5には標準関数Object.create。大幅に簡略化されたバージョンは次のようになります。

Object.create = function(prototype) {
    var Type = function () {};
    Type.prototype = prototype;
    return new Type();
};

コンストラクター関数を作成してからnewで呼び出すという苦痛を単に処理します。

いつプロトタイプを避けますか?

便利な比較は、人気のあるOO JavaおよびC#などの言語です。これらは2種類の継承をサポートします。

  • interface継承。ここで、implementおよびinterfaceを使用して、クラスのすべてのメンバーに対して独自の実装を提供します。インタフェース。
  • implementation継承。いくつかのメソッドのデフォルト実装を提供するextend a class

JavaScriptでは、プロトタイプ継承は一種の実装継承です。そのため、(C#またはJavaで)デフォルトの動作を得るために基本クラスから派生した状況では、オーバーライドを介して小さな変更を行い、JavaScriptでプロトタイプの継承が意味を持ちます。

ただし、C#またはJavaでインターフェースを使用する場合は、JavaScriptで特定の言語機能を使用する必要はありません。インターフェイスを表す何かを明示的に宣言する必要はなく、オブジェクトをそのインターフェイスを「実装する」とマークする必要もありません。

var duck = {
    quack: function() { ... }
};

duck.quack(); // we're satisfied it's a duck!

言い換えると、オブジェクトの各「タイプ」に「メソッド」の独自の定義がある場合、プロトタイプから継承することには価値がありません。その後、各タイプに割り当てるインスタンスの数に依存します。しかし、多くのモジュール設計では、特定のタイプのインスタンスは1つだけです。

そして実際、 実装の継承は悪であることが多くの人々から示唆されています 。つまり、型に一般的な操作がある場合、ベース/スーパークラスに入れずに、オブジェクトを渡すモジュールの通常の関数として公開する方がわかりやすいかもしれませんあなたは彼らに作用してほしい。

129

オブジェクトの「非静的」メソッドを宣言する場合は、プロトタイプを使用する必要があります。

var myObject = function () {

};

myObject.prototype.getA = function (){
  alert("A");
};

myObject.getB = function (){
  alert("B");
};

myObject.getB();  // This works fine

myObject.getA();  // Error!

var myPrototypeCopy = new myObject();
myPrototypeCopy.getA();  // This works, too.
44
KeatsKelleher

組み込みのprototypeオブジェクトを使用する理由の1つは、共通の機能を共有するオブジェクトを複数回複製する場合です。プロトタイプにメソッドをアタッチすることにより、各newインスタンスごとに作成される複製メソッドを節約できます。しかし、メソッドをprototypeにアタッチすると、すべてのインスタンスがそれらのメソッドにアクセスできます。

ベースCar()クラス/オブジェクトがあるとします。

_function Car() {
    // do some car stuff
}
_

その後、複数のCar()インスタンスを作成します。

_var volvo = new Car(),
    saab = new Car();
_

これで、各車が運転、電源投入などを必要とすることがわかります。メソッドをCar()クラスに直接アタッチする代わりに(作成された各インスタンスごとにメモリを占有します)、代わりにプロトタイプ(一度だけメソッドを作成)、したがって、新しいvolvosaabの両方にそれらのメソッドへのアクセスを許可します。

_// just mapping for less typing
Car.fn = Car.prototype;

Car.fn.drive = function () {
    console.log("they see me rollin'");
};
Car.fn.honk = function () {
    console.log("HONK!!!");
}

volvo.honk();
// => HONK!!!
saab.drive();
// => they see me rollin'
_
16
hellatan

特定の種類のオブジェクトのコピーを大量に作成し、それらがすべて共通の動作を共有する必要がある場合、プロトタイプオブジェクトに関数を配置します。そうすることで、各関数のコピーを1つだけ持つことでメモリを節約できますが、それは最も単純な利点にすぎません。

プロトタイプオブジェクトのメソッドを変更するか、メソッドを追加すると、対応するタイプのすべてのインスタンスの性質が即座に変更されます。

正確になぜこれらすべてを行うのは、ほとんどが独自のアプリケーション設計の機能であり、クライアント側のコードで行う必要がある種類のことです。 (まったく異なる話は、サーバー内のコードです。そこでより大規模な「OO」コードを実行することを想像するのははるかに簡単です。)

12
Pointy

クラスベースの用語で説明すると、Personはクラス、walk()はPrototypeメソッドです。したがって、walk()は、これで新しいオブジェクトをインスタンス化した後にのみ存在します。

したがって、Person uのようなオブジェクトのコピーを作成したい場合、Prototypeはメモリ内のオブジェクトごとに同じ関数のコピーを共有/継承することでメモリを節約するため、優れたソリューションです。

一方、静的はそのようなシナリオではそれほど大きな助けにはなりません。

function Person(){
this.name = "anonymous";
}

// its instance method and can access objects data data 
Person.prototype.walk = function(){
alert("person has started walking.");
}
// its like static method
Person.ProcessPerson = function(Person p){
alert("Persons name is = " + p.name);
}

var userOne = new Person();
var userTwo = new Person();

//Call instance methods
userOne.walk();

//Call static methods
Person.ProcessPerson(userTwo);

そのため、インスタンスメソッドに似ています。オブジェクトのアプローチは、静的メソッドに似ています。

https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript

2
Anil Namde