JavaScriptでプロトタイププログラミングを使用する場合


15

私は、プロジェクト用のシンプルなウィジェットを次の方法で開発することにかなりの時間を費やしました。

var project = project || {};

(function() {

  project.elements = {
    prop1: val1,
    prop2: val2
  }

  project.method1 = function(val) {
    // Do this
  }

  project.method2 = function(val) {
    // Do that
  }

  project.init = function() {
    project.method1(project.elements.prop1)
    project.method2(project.elements.prop2)
  }
})()

project.init();

しかし、フォーマットを次のように変更し始めました。

function Project() {
  this.elements = {
    prop1: val1,
    prop2: val2
  }

  this.method_one(this.elements.prop1);
  this.method_two(this.elements.prop2);
}

Project.prototype.method_one = function (val) {
  // 
};

Project.prototype.method_two = function (val) {
  //
};

new Project();

確かに、これらは馬鹿げた例なので、アクセルに巻き付けないでください。しかし、機能の違いは何ですか、いつどちらを選ぶべきですか?


プロジェクトはスコープを離れないため、最初のコード例は機能しないと思います。JSで継承を使用するには、プロトタイピングを使用します。最初の例はプロジェクトを拡張するためのものではないため、再利用性が制限される場合があります。
-Aitch

うん、私は誤ってproject宣言を関数の中に入れました。更新しました。
JDillon522

こっちも一緒。最初の例は静的で、2番目の例はオブジェクト指向です。
Aitch

1
オブジェクトの1つのインスタンスのみを使用している場合、プロトタイプ定義を使用する理由はまったくありません。そして、あなたが必要と思われるもの-モジュール形式です-そのための多くのオプションがあります:addyosmani.com/writing-modular-js
c69

1
シングルトンパターンの最初の1つ。シングルトン以外の1つ(1つのクラスが多くのオブジェクトを持つことができる場合)
-Kokizzu

回答:


6

最初の違いは次のように要約できます:インスタンスをthis指します。クラスのをます。Definitionをprototype指します。

次のクラスがあるとしましょう:

var Flight = function ( number ) { this.number = number; };

そのため、ここthis.numberではクラスのすべてのインスタンスにアタッチしています。Flight独自のフライト番号が必要ます。

var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );

対照的に、prototypeすべてのインスタンスがアクセスできる単一のプロパティを定義します。

フライト番号を取得したい場合は、次のスニペットを書くだけで、すべてのインスタンスがこの新しくプロトタイプ化されたオブジェクトへの参照を取得します。

Flight.prototype.getNumber = function () { return this.number; };

2番目の違いは、JavaScriptがオブジェクトのプロパティを検索する方法に関するものです。あなたが探しているときObject.whatever、JavaScriptはメインまでずっと行きます Objectオブジェクト(他のすべてのものが継承しているオブジェクト)に到達し、一致するものが見つかるとすぐにそれを返すか呼び出します。

しかし、それはプロトタイプ化されたプロパティでのみ起こります。だから、もしあなたがより高い層のどこかにいるならthis.whatever、JavaScriptはそれを一致と見なさず、検索を続行します。

それが実際にどのように起こるか見てみましょう。

[ほとんど]すべてがJavaScriptのオブジェクトであることに注意してください。これを試して:

typeof null

次に、内部の内容を確認しましょうObject(大文字O.最後に注意してください)。Google Chromeのデベロッパーツールでを入力すると、.その特定のオブジェクト内で使用可能なプロパティのリストが表示されます。

Object.

次に同じことを行いFunctionます:

Function.

nameメソッドに気付くかもしれません。行って起動して、何が起こるか見てみましょう:

Object.name
Function.name

それでは、関数を作成しましょう。

var myFunc = function () {};

そして、nameメソッドもここにあるかどうかを見てみましょう:

myFunc.name

空の文字列を取得する必要がありますが、大丈夫です。エラーや例外は発生しません。

では、その神のようなものに何かを追加しObjectて、他の場所でも同様に入手できるかどうかを確認しましょう。

Object.prototype.test = "Okay!";

そしてそこに行きます:

Object.prototype.test
Function.prototype.test
myFunc.prototype.test

すべての場合であなたは見るべき"Okay!"です。

各メソッドの長所と短所については、各オブジェクトのプロパティ全体をコピーするのではなく、すべてのインスタンスへの参照を保持するため、プロトタイピングを「より効率的な」方法として考えることができます。一方、それはあなたが本当に理由を正当化することができるまでの大きなノーノーである密結合の例です。thisコンテキストに関連しているため、かなり複雑です。インターネットで無料で多くの優れたリソースを見つけることができます。

つまり、どちらの方法も単なる言語ツールであり、それはあなたとあなたが解決しようとしている問題に本当に依存しており、より適切なものを選択します。

クラスのすべてのインスタンスに関連するプロパティが必要な場合は、を使用しますthis。すべてのインスタンスで同じように機能するプロパティが必要な場合は、を使用しますprototype

更新

サンプルスニペットに関して、最初のサンプルはSingletonの例です。そのため、thisオブジェクト本体内で使用するのが理にかなっています。このようにモジュール化することで、サンプルを改善することもできます(常に使用する必要はありませんthis)。

/* Assuming it will run in a web browser */
(function (window) {
    window.myApp = {
        ...
    }
})( window );

/* And in other pages ... */
(function (myApp) {
    myApp.Module = {
        ...
    }
})( myApp );

/* And if you prefer Encapsulation */
(function (myApp) {
    myApp.Module = {
         "foo": "Foo",
         "bar": function ( string ) {
             return string;
         },
         return {
             "foor": foo,
             "bar": bar
         }
    }
})( myApp );

最初に使用しているので、あなたの第二のスニペットは、そのあまり意味がないthisと、後であなたがそれをハックしようとしているprototypeので、仕事をしない、thisより優先されますprototype。そのコードからどのような期待があり、どのように機能していたのかはわかりませんが、リファクタリングすることを強くお勧めします。

更新

this優先順位について詳しく説明するためにprototype、例を示して説明の方法を説明しますが、バックアップする外部リソースはありません。

例は非常に簡単です。

var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";

var obj = new myClass;
obj.foo;     // Still contains "Foo" ...
obj.bar;     // Contains "Bar" as expected

私たちが知っているように、説明はthis文脈に関連しています。そのため、コンテキストの準備ができるまで存在しません。コンテキストの準備ができたら?新しいインスタンスが作成されているとき!あなたは今残りを推測する必要があります!prototype定義はありthisますが、その時点で作成される新しいインスタンスがすべてであるため、優先する方が理にかなっています。


これは部分的に驚くほど素晴らしい答えです!それを編集して、2つの方法を比較および対比してさらに詳しく説明できますか?最初の2つの段落では、どの設計方法を参照しているのかがわかりません。あなたの運動は素晴らしいです!私はそのようなプロトタイピングの力についてあまり考えませんでした。また、各方法をいつ使用するかの半詳細な使用例を示してもらえますか?再びありがとう、これは素晴らしい。
JDillon522

@ JDillon522それを聞いてうれしい。数時間以内に更新を試みます!
53777A

@ JDillon522簡単な更新を行いました。今回はより明確になることを願っています。
53777A

@ JDillon522 Aもう少しあなたのサンプルスニペットについて...
...-53777A

素敵なシングルトンの例。メソッドを含む独自のプロパティを参照するthisため、愚かなプロトタイプの例で使用しましたthis。私はコードについて読むことから最善を学ぶことはできませんが、コードを見ることから多くを学びます。(MDNのビットObject Playground(驚くべき)、その他いくつか)。あなたは何を意味するかについて説明して何かを指すことができる「this優先順位を引き継ぎますprototypeか?もっと調べたいです。
JDillon522
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.