保守可能なオブジェクト指向 JavaScript コードを作成できると、コストが節約されるだけでなく、人気も高まります。信じないで?いつかあなたまたは他の誰かが戻ってきて、あなたのコードを再利用する可能性があります。この経験をできるだけ苦痛から減らすことができれば、時間を大幅に節約できます。地球上の誰もが時は金なりであることを知っています。同様に、誰かの悩みを解決することで、その人の好意を得ることができるかもしれません。ただし、保守可能なオブジェクト指向 JavaScript コードの記述方法を検討する前に、オブジェクト指向とは何かを簡単に見てみましょう。オブジェクト指向の概念をすでに理解している場合は、次のセクションを直接スキップできます。
オブジェクト指向とは何ですか?
オブジェクト指向プログラミングは、主にコードを通じて現実世界の物理オブジェクトを表します。オブジェクトを作成するには、まずそれを定義する「クラス」を作成する必要があります。 クラスは、アカウント、従業員、ナビゲーション メニュー、車、植物、広告、飲み物など、ほぼあらゆるものを表すことができます。そして、オブジェクトを作成するたびに、クラスからオブジェクトをインスタンス化します。つまり、クラスのインスタンスがオブジェクトとして作成されます。実際、オブジェクトは通常、同じタイプの複数のものを扱うときに使用されます。さらに、単純な関数型プログラムだけでも素晴らしい仕事をすることができます。オブジェクトは基本的にデータのコンテナです。したがって、従業員オブジェクトには、従業員番号、名前、入社日、役職、給与、年功などを保存することができます。オブジェクトには、データを処理する関数 (「メソッド」とも呼ばれます) も含まれています。メソッドは、データの整合性を確保し、保存前にデータを変換するための仲介として使用されます。たとえば、メソッドは任意の形式の日付を受け入れ、それを保存する前に標準化された形式に変換できます。最後に、クラスは他のクラスから継承することもできます。継承により、同じコードを異なるクラスで再利用できます。たとえば、銀行口座とビデオ ストアのアカウントはどちらも、個人情報、口座開設日、支店情報などを含む基本的な口座クラスを継承できます。その後、それぞれがトランザクションまたはローン処理のための独自のデータ構造とメソッドを定義できます。
警告: JavaScript のオブジェクト指向は同じではありません
前のセクションでは、古典的なオブジェクト指向プログラミングの基本について概説しました。古典的と言ったのは、JavaScript がこれらのルールに従っていないからです。対照的に、JavaScript クラスは関数として記述され、継承はプロトタイプを通じて実装されます。プロトタイプの継承は基本的に、クラスからクラスを継承するのではなく、プロトタイプのプロパティを使用してオブジェクトの継承を実装することを意味します。
オブジェクトのインスタンス化
以下はJavaScriptでのオブジェクトのインスタンス化の例です:
// Employeeクラスを定義します
function Employee(num, fname, lname) {
this.getFullName = function () {
return fname + " " + lname ;
}
};
// Employee オブジェクトをインスタンス化します
var john = new Employee("4815162342", "John", "Doe");
alert("従業員のフルネームは " + john.getFullName( ) );
ここで、注意すべき重要な点が 3 つあります:
1 「クラス」関数名の最初の文字は大文字にする必要があります。これは、関数が通常の関数のように呼び出されるのではなく、インスタンス化されることを目的としていることを示します。
2 new 演算子はインスタンス化中に使用されます。 new を省略して関数を呼び出すだけだと、多くの問題が発生します。
3 getFullName はこの演算子に割り当てられているため、公開されていますが、fname と lname は公開されていません。 Employee 関数によって生成されたクロージャは、getFullName に fname および lname へのアクセスを与えますが、他のクラスに対してはプライベートのままです。
プロトタイプの継承
以下は、JavaScript でのプロトタイプの継承の例です。
// Human クラスを定義します。
function Human() {
this.setName = function (fname, lname) {
this.fname = fname;
this. lname = lname ;
}
this.getFullName = function () {
return this.fname + " " + this.lname;
}
}
// 従業員クラスを定義する
function Employee(num) {
this.getNum = function ( ) {
return num;
}
};
// Employee に Human クラスを継承させる
Employee.prototype = new Human();
// Employee オブジェクトをインスタンス化する
var john = new Employee("4815162342 」 );
john.setName("John", "Doe");
alert(john.getFullName() + "の従業員番号は " + john.getNum());
今回作成した Human クラスにはすべてが含まれています人間に共通のプロパティ - 従業員だけが名前を持っているわけではなく、誰もが名前を持っているため、fname と lname も入れました。次に、Human オブジェクトをそのプロトタイプ プロパティに割り当てます。
継承によるコードの再利用
前の例では、元の Employee クラスが 2 つの部分に分割されました。すべての共通の人間属性は Human クラスに移動され、その後 Employee が Human を継承しました。この場合、Human のプロパティは、Student、Client、Citizen、Visitor などの他のオブジェクトによって使用できます。これがコードを分割して再利用するための優れた方法であることに気づいたかもしれません。 Human オブジェクトを扱う場合、異なるオブジェクトを 1 つずつ再作成するのではなく、Human を継承して既存のプロパティを使用するだけで済みます。また、「ミドルネーム」属性を追加したい場合は一度追加するだけで、Humanクラスを継承しているものはすぐに利用することができます。逆に、「ミドルネーム」属性をオブジェクトに追加したいだけの場合は、Human クラスに追加せずに、そのオブジェクトに直接追加できます。
1. パブリックとプライベート
次のトピックでは、クラスのパブリック変数とプライベート変数について話したいと思います。オブジェクト内でのデータの処理方法に応じて、データはプライベートまたはパブリックとして扱われます。私有財産は、必ずしも他人がアクセスできないことを意味するものではありません。おそらく、特定の方法のみを使用する必要があります。
● 読み取り専用
オブジェクトの作成時に値だけが必要な場合があります。作成したら、他の人にこの値を変更させたくないでしょう。これを行うには、プライベート変数を作成し、インスタンス化中にそれに値を割り当てます。
function Animal(type) {
var data = [];
data['type'] = type;
this.getType = function () {
return data['type'];
}
}
varふわふわ= new Animal('dog');
fluffy.getType(); // Return 'dog'
この例では、Animal クラスにローカル配列データが作成されます。 Animal オブジェクトがインスタンス化されると、 type の値が渡され、その値がデータ配列に配置されます。プライベートであるため、値を上書きすることはできません (Animal 関数がそのスコープを定義します)。オブジェクトがインスタンス化されると、型値を読み取る唯一の方法は getType メソッドを呼び出すことです。 getType は Animal で定義されているため、Animal によって生成されたクロージャを使用してデータを入力できます。この場合、オブジェクトの型を読み取ることはできますが、変更することはできません。
非常に重要な点の 1 つは、オブジェクトが継承される場合、「読み取り専用」テクノロジーは使用できないということです。継承が実行された後、インスタンス化された各オブジェクトはそれらの読み取り専用変数を共有し、その値を上書きします。最も簡単な解決策は、クラス内の読み取り専用変数をパブリック変数に変換することです。ただし、それらは非公開にしておく必要があります。フィリップがコメントで言及したテクニックを使用できます。
●パブリック
もちろん、特定の属性の値を自由に読み書きしたい場合もあります。これを実現するには、this 演算子を使用します。
function Animal() {
this.mood = '';
}
var Fluffy = new Animal();
Fluffy.mood = 'happy';
Fluffy.mood // 今度は 'happy' を返します
;このクラスは、自由に読み書きできる、mood と呼ばれるプロパティを公開します。同様に、前の例の getType 関数などの関数をパブリック プロパティに割り当てることができます。 getType に値を代入しないように注意してください。代入しないと、値が破棄されてしまいます。
完全にプライベート
最後に、完全にプライベートなローカル変数が必要であることがわかるかもしれません。こうすることで、パブリック メソッドを作成せずに、最初の例と同じパターンを使用できます。
function Animal() {
var Secret = "You'll Never know!"
}
var purple = new Animal();
2. 柔軟な API を作成します
クラスの作成について説明しました。製品要件との一貫性を保つことは同期的に変化するため、コードが古くならないようにする必要があります。すでにいくつかのプロジェクトを実行したり、製品を長期間保守したりしたことがある場合は、要件が変化することを知っておく必要があります。これは議論の余地のない事実です。そう考えないと、コードは書かれる前に駄目になってしまいます。タブのコンテンツを突然アニメーション化したり、Ajax 呼び出しを通じてデータを取得したりする必要が突然必要になる場合があります。未来を正確に予測することは不可能ですが、将来の緊急事態に備える柔軟なコードを記述することは可能です。
● Saner パラメータ リスト
パラメータ リストを設計するときに、コードを前向きにすることができます。パラメーター リストは、他のユーザーがコードを実装するための主な連絡先であり、適切に設計されていない場合、非常に問題が発生する可能性があります。次のようなパラメータ リストは避けてください:
function Person(employeeId, fname, lname, tel, FAX, email, email2, dob) {
};
このクラスは非常に脆弱です。コードを公開した後にミドルネームパラメータを追加する場合は、順序の問題によりリストの最後に追加する必要があります。これでは仕事が面倒になります。各パラメータに値を割り当てないと、非常に困難になります。例:
var ara = new Person(1234, "Ara", "Pehlivanian", "514-555-1234", null, null, null, "1976-05-17");
パラメーター リストを操作するためのより適切で柔軟な方法は、次のパターンを使用することです:
function Person(employeeId, data) {
};
最初のパラメーターは必須であるため、最初のパラメーターがあります。残りはオブジェクトに混ぜて柔軟に使用できます。
var ara = 新しい人物(1234, {
fname: "Ara",
lname: "Pehlivanian",
tel: "514-555-1234",
dob: "1976-05-17"
});
このパターンの利点は、読みやすく、柔軟性が高いことです。 FAX、電子メール、および電子メール 2 は完全に無視されることに注意してください。それだけでなく、オブジェクトは特定の順序ではないため、都合の良い場所にミドルネームパラメータを追加するのは非常に簡単です:
var ara = new Person(1234, {
fname: "Ara",
mname: "Chris",
lname: "Pehlivanian",
tel: "514-555-1234",
dob: "1976-05-17"
});
クラス内の値は次からアクセスできるため、重要ではありません。インデックス:
function Person(employeeId, data) {
this.fname = data['fname'];
};
data['fname'] が値を返す場合、その値は設定されます。そうでなければ、正しく設定されていなくても、損はありません。
● コードを埋め込み可能にする
時間の経過とともに、製品要件によりクラスの動作がさらに必要になる場合があります。ただし、この動作はクラスのコア機能とは何の関係もありません。また、別のタブから外部データを取得するときに、あるタブのパネル内のコンテンツをグレー表示にするなど、クラスの唯一の実装になる場合もあります。これらの関数をクラス内に置きたいと思うかもしれませんが、それらはそこには属しません。タブ ストリップの役割は、タブを管理することです。アニメーション化とデータの取得はまったく異なるものであり、タブ ストリップのコードから分離する必要があります。追加の機能を排除せずにタブ ストリップを将来にわたって使用できる唯一の方法は、動作をコードに埋め込むことです。つまり、イベントを作成し、それをコード内の重要な瞬間 (onTabChange、afterTabChange、onShowPanel、afterShowPanel など) にフックします。そうすれば、onShowPanel イベントに簡単にフックして、パネルのコンテンツをグレー表示にするハンドラーを作成でき、誰もが満足できます。 JavaScript ライブラリを使用すると、これを簡単に行うことができますが、自分で記述するのはそれほど難しくありません。以下は YUI 3 を使用した例です。
< script type="text/javascript">
YUI().use('event', function (Y) {
function TabStrip() {
this.showPanel = function () {
This.fire('onShowPanel' ; common Y.Augment(Y.EventTarget)をトリガーする能力をタブストリップします。 // パネルを表示する前に行うべきその他の作業}}); 次に行うこと
);この例には、showPanel メソッドを備えた単純な TabStrip クラスがあります。このメソッドは、onShowPanel と afterShowPanel という 2 つのイベントを起動します。この機能は、Y.EventTarget を使用してクラスを拡張することで実現されます。それが完了したら、TabStrip オブジェクトをインスタンス化し、それに一連のハンドラーを割り当てます。これは、現在のクラスを混乱させることなく、インスタンスの動作のみを処理するための一般的なコードです。
まとめ
同じページ上、同じ Web サイト内、またはプロジェクト間でコードを再利用する予定がある場合は、コードをパッケージ化してクラス内に整理することを検討してください。オブジェクト指向 JavaScript は、自然にコードの編成とコードの再利用を容易にします。さらに、少し先見の明があれば、コードを作成した後も長く使用できる柔軟性を確保することができます。再利用可能で将来性のある JavaScript コードを作成すると、あなた、あなたのチーム、会社の時間とお金が節約されます。これは間違いなくヒットします。