2012-04-02 13 views
4

私はJavaScriptでOOプログラミングを学んでおり、クラスを作成する方法はたくさんあるようです。私は一般的な構造を読んだものの多くを蒸留することができましたが、肥大化を避けるためにプロトタイピングの目的が不足しているような気がします。この「クラス」のプロトタイプ定義を含めると、無意味になります(オブジェクトのサイズを縮小しない)か?この全体的な構造に欠陥がありますか?JavaScriptの適切なクラス構成

おかげで、

var Car = (function() { 

    //Private fields 
    var _make; 
    var _model; 

    //Constants (protected by encapsulation)  
    var NUM_OF_WHEELS = 4; 

    //Private methods 
    function getDesc() { 
     return _make + " " + _model; 
    } 

    //Public constructor 
    function thisCar(make, model, color) { 
     _make = make; 
     _model = model; 

     //public properties 
     thisCar.prototype.color = color; 
    } 

    //static properties 
    thisCar.carsInTheWorld = 50; 

    //static methods 
    thisCar.getNumberOfWheels = function() { 
     return NUM_OF_WHEELS * thisCar.carsInTheWorld; 
    }; 

    //public properties 
    thisCar.prototype.color = ""; 

    //public method 
    thisCar.prototype.startEngine = function() { 
     console.log(getDesc() + " engine started"); 
    }; 

    return thisCar; 
})(); 

EDIT コメントや、ここで提供されたリンクを読んだ後、私は理解するものです。

プライベートメンバーへのアクセスを必要とするクラスのメンバーは、プロトタイプに追加することはできず、特権が必要です。同様に、コンストラクタ関数にプロトタイプを含めないのが一般的です。

var Car = function (make, model, color) {//Public constructor 
    //Private fields 
    var _make = make; 
    var _model = model; 

    //Public fields 
    this.color = color; 

    //Private methods 
    function getDesc() { 
     return _make + " " + _model; 
    } 

    //Privileged functions (requiring private members) 
    this.startEngine = function() { 
     console.log(getDesc() + " engine started"); 
    }; 
}; 

//public method 
Car.prototype.sprayPaint = function (newColor) { 
    var oldColor = this.color; 
    this.color = newColor; 
    console.log("Your car has changed from " + oldColor + " to " + newColor); 
}; 

//Public fields (if not declared in constuctor) 
Car.prototype.fuel = 0; 

//static properties 
Car.carsInTheWorld = 0; 

//static methods 
Car.getNumberOfWheels = function() {    
    var NUM_OF_WHEELS = 4; 
    return NUM_OF_WHEELS * Car.carsInTheWorld; 
}; 

本当にありがとうございました。

+3

JSのこの種のコーディングは、個人的には私を嫌にします。それは信じられないほど動的な言語であり、あなたは正しい - すべてを行う多くの方法がある。私はあなたに最終的にJS.Classのようなクラスフレームワークを使用することを切望しています。 –

+3

あなたのコードには多くの問題がありますが、ここで詳しく説明するにはあまりにも多くの問題があります。 JSの正しい*継承のタイプについては、私の投稿を見ることができます。http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html –

+0

コードを見ると、 [MDN](https://developer.mozilla。Object Oriented Javascript – Starx

答えて

0

これはほとんど問題ありません。ただし、このビットは間違っています。

プロトタイプには何も割り当てないでください。これは、コンストラクタから作成されたすべてのCarsにcolorプロパティを割り当てます。

代わりには、次の操作を行います。

this.color = color; 

と一般的な質問に答えるためには、試作品をこのように使用することは無意味ではありません。外部関数は、スクリプトが解析された直後に1回だけ実行されます。内部thisCarコンストラクタをCarに割り当てます。上記の例外を除き、プロトタイプのプロパティは適切に配置されます。

しかし、もう1つの提案は、あなたのIIFEの内部でさえ、その名前に大文字の頭文字を使用することです。私は個人的にはここでもCarを使っています。

編集:私は最初に見たよりも多くの間違っあり

。これも間違っています

var _make; 
var _model; 

// [ ... ] 
function thisCar(make, model, color) { 
    _make = make; 
    _model = model; 
} 

これらはインスタンスプロパティではありません。

また、プロトタイプの使用とクロージャーベースのプライベートプロパティを組み合わせることが実際にはわかりません。だから私はあなたがあまりにも多くをやろうとしていると思う。代わりにプロトタイプを使用しての

3

は、一般的なパターンは、あなたのパブリックアクセサ/ミューテータが含まれているコンストラクタからオブジェクトを返すことです:

jsfiddle

function Car() { 
    var myPrivateVar = "foo"; 
    var myPublicVar = "bar"; 

    function myPrivateFunc() {console.log(myPrivateVar);}; 
    myPrivateFunc();  

    return { 
    getMyPublicVar: function() { 
     return myPublicVar; 
    } 
    } 
} 
var honda = Car(); 
console.log(honda.getMyPublicVar()); 
honda.myPrivateFunc(); // fail 
プロパティを追加するには、クラス定義の外

使用プロトタイプそれに。Carがすでに定義されている場合はCar.prototype.myFunc = function() {};を使用して、myFuncCarのオブジェクトを将来インスタンス化するとします。これらの追加メンバーは公開されています。

Here's a question that should help you

Here's the standard article from Crockford on doing inheritance this way.

私はあなたのコードが大きくなったときに、このようなJS.Classとしてクラスのフレームワークを使用すると、あなたに数え切れないほどの頭痛の種を保存することを繰り返す必要があります。

+0

いいえ。コンストラクタはオブジェクトを返さない(しない)必要があります。 – Bergi

+0

申し訳ありませんが、私の構造は少し間違っていました。それはコンストラクタではなく、コンストラクタです。 OOの意味では、あなたは 'new Car()'を呼び出さないという点で技術的なJavaScriptの意味ではありません。しかし、それでもCar()から返されるプライバシーとインターフェイスを持つことができるクロージャが作成されます。 –

+0

コンストラクタや関数として呼び出せるネイティブJSコンストラクタがたくさんあります。たとえば文字列。あなたのリターン・ステートメントをブランチすることは私には良い考えですが、リターンの時点でプロセスを停止する以外に、オブジェクトのインスタンス化には何の影響もないと思います。 –

2

クロージャとオブジェクト指向のコンストラクタを混在させました。通常、クロージャなしで開始します。 JSでは、コンストラクタ関数で「クラス」を定義します。

var Car = function Car(model) { //Public constructor 

    // Private fields of one instance 
    // model is an argument 
    var make; 

    // Private methods of one instance 
    function getDesc() { 
     return make + " " + model; 
    } 

    // Public fields of one instance 
    this.color = "#555"; 

    // Public methods of one instance, privileged the access private fields and functions 
    this.setMake = function(m) { 
     make = m; 
    }; 
    this.desc = function() { 
     return getDesc(); 
    }; 
} // end of constructor 

/* now the prototype things: */ 

// public "default" fields, may get overwritten per instance 
Car.prototype.color = ""; 

// public methods, can only access other public things (not "privileged") 
thisCar.prototype.startEngine = function() { 
    console.log(this.desc() + " engine started"); 
}; 

これはそれです。今、静的なものを追加することができます。彼らはCar関数とは関係ありませんが、多くの場合、コンストラクタのプロパティによって名前空間を取得します。しかし、それらは自由変数でもあり得る。

var carsInTheWorld = 50; 
// or 
Car.livingInstances = 50; 
// or something 

Car.NUM_OF_WHEELS = 4; // constants are uppercase 

静的でプライベートな変数が必要な場合のみ(例: instances-counter - すべてを囲むクロージャを作成することができます。次に、その変数を取り除かれた変数は、そのクロージャー関数の内部からのみアクセス可能です。

+0

this.descは本質的にプライベートにならないgetDesc()を公開していませんか?ここでの問題は、プロトタイプとプライベートメソッド/変数にメソッドを追加することを実際に混ぜることはできないと思います。 – Phillip

+0

はい、この例では、これは 'this.desc = getDesc;'とほぼ同じです。しかし私は、特権的な機能で私的な機能の使い方を示したかっただけです。別の例を追加する。 – Bergi

2

インスタンスのコンストラクタ関数に直接添付されたメソッドのバックアップリポジトリとして、prototypeを考えてみましょう。それを持たないインスタンスでプロパティ/メソッドを呼び出そうとすると、そのインスタンスのコンストラクタのプロトタイプがそのメソッドに対してチェックされます。バーンマーは、プロトタイプのプロパティはインスタンスの内部を見ることができない(インスタンス変数にアクセスする)ことです。

複雑なクラスのような継承スキームを可能にするために、プロトタイプをチェーンするライブラリをすぐに突き止めないようにすることをお勧めします。

このアプローチが悪臭を帯びやすいためです。柔軟性がなく、読みにくく、JSが最初に扱う問題の種類にはあまり適していません。 (実際には、このようなスキームは過度であり、どの言語でも推奨されていません)。私は継承が悪いと言っているわけではありません.JavaScriptの聖杯は悪いJavaを書くのではなく、20日間のカスケード継承の深層セットを見て、カップルの日を見ていない人は完全に解読不能です彼らは最近。

カプセル化について心配する必要はありません。いいえ。最後に、フロントエンドやUI開発者が複雑な電子商取引サイトでjQueryの重要な部分を書き直したり、JQオブジェクトメソッドやその他のプロパティを直接変更したりすることについて聞いたことがあります。他のものは壊れるかもしれない? Pythonの子供たちが言うように、 "信頼するユーザー"。プライベートインスタンス変数は、インターフェイスとそれ以外のインターフェイスを明確にするのに役立ちます。このユーティリティ以外にも、皆さんがいつも私たちのコードをいつも見ることができる、あなたの心とインターネット上に置いてください。

JSの機能に関するすべてのことを学びます。そこには、コンポーザーよりもインスタンスに焦点を当てる傾向のあるJS OOPで役に立つことがたくさんあります。関数、コンテキスト、呼び出し/適用メソッドは、あなたのために働く構造体を考え出すための鍵です。

+0

正直言って、これまでのところ、オブジェクトリテラルはこれまで以上に十分でした。私はOOをサーバ上に保つのが好きです。しかし、私は本当に言語と「ベスト」プラクティスを理解したかったのです。クラスは良い学習ツールのようです。 – Phillip

+0

FYI私はあなたの回答が好きで、カプセル化と継承があまりにも多くは避けようとしますが、もう一方の回答は質問に近いものでした。 – Phillip

+0

私は怒っていません。私はちょうどよく説明されていないプロトタイプのプロパティを手助けしたいと思います。物事を暴言するような言い訳に飛びついて、残りのものを取りなさい。私はまた、フードの中でjQueryを理解し、大きなOOPパラダイムの多く(たとえJSの多くの目的に役立たないパターンであっても私にアイデアを与えていたとしても)の言語コンテキストのためのDesign Patternsを読むことをお勧めします。 –

関連する問題