JavaScript オブジェクト指向 データの新しい理解 encapsulation_js オブジェクト指向

WBOY
リリース: 2016-05-16 18:40:21
オリジナル
913 人が閲覧しました

今日は主に、JavaScript スクリプトでデータのカプセル化を実装する方法について説明します。
データのカプセル化とは、単に、発信者に見られたくないコンテンツを隠すことを意味します。これはオブジェクト指向プログラミングの 3 つの要素のうちの 1 つ目であり、他の 2 つは継承とポリモーフィズムです。
データのカプセル化の実装については、C、Java、C# などの言語では、public、private、static などのキーワードによって実装されます。 JavaScript では、まったく異なる形式になります。特定の形式のデータ カプセル化を具体的に実装する方法について説明する前に、よく知られているものの見落とされがちな JavaScript の単純な概念について最初に説明します。
1 いくつかの基本概念
1.1 変数の定義
JavaScript 言語では、変数は var キーワードを通じて定義されます。
しかし、var を使用して定義されていない変数に値を直接代入すると、この変数はグローバル変数になります。
一般に、var で定義されていない変数の使用は避けるべきです。主な理由は、グローバル変数へのアクセスはローカル変数よりもはるかに遅いため、プログラムの実行効率に影響するためです。
しかし、この使用法では、変数がグローバル変数でなければならないことが保証されます。
さらに、速度を確保するために、グローバル変数を使用する場合、var を介してローカル変数を定義し、そのグローバル変数をそれに割り当てることで、グローバル変数のローカル参照を取得できます。
1.2 変数の型
未定義の変数の型は未定義です。
変数の値は関数にすることができます。
関数は JavaScript のクラスとして機能できます。
1.3 変数スコープ
変数スコープとは、変数のライフサイクルの有効範囲を指します。
単に { } で作成されたブロックではスコープを作成できません。
with は、それに含まれるオブジェクトのスコープを現在のスコープ チェーンに追加しますが、新しいスコープは作成しません。 with ブロックが終了すると、オブジェクト スコープは現在のスコープ チェーンから削除されます。
try-catch では、catch のエラー オブジェクトは catch ブロック内でのみ有効ですが、catch ブロック内で定義された変数は現在のスコープに属します。
if、for、for-in、while、do-while、switch などの他の制御ステートメントによって作成されたブロックはスコープを作成できません。
function で作成された関数は、新しいスコープを作成し、現在のスコープに追加します。
2 カプセル化
具体的なカプセル化について説明します。まず、最もよく知られているカプセル化である、プライベート インスタンス メンバー、パブリック インスタンス メンバー、パブリック 静的メンバーについて説明します。最後に、あまり馴染みのないプライベート静的メンバーと静的クラスのカプセル化方法について説明します。以下で説明するのはオブジェクト指向プログラミングであるため、関数がクラスとして定義されて使用される場合、それを仮にクラスと呼びます。
2.1 プライベート インスタンス メンバー
JavaScript のプライベート インスタンス メンバーは、実際には関数内のローカル変数を使用して実装できます。これは、クラスのプライベート インスタンス メンバーと同等です。例:

コードをコピー コードは次のとおりです。

class1 = function() {
// プライベートフィールド
var m_first = 1;
var m_second = 2;
// プライベートメソッド
function method1() {
alert(m_first);
var method2 = function() {
alert(m_second);
// コンストラクター
{
method2();
}
var o = new class1();
// エラー
o.method1();
ここで、m_first と m_second は class1 の 2 つのプライベート インスタンス フィールド、method1 と method2 は 2 つのプライベート インスタンス メソッドです。これらは、このクラスのオブジェクト内でのみ使用でき、オブジェクトの外では使用できません。
ここでは、プライベート メソッドを作成するには 2 つの方法があることがわかります。1 つはクラス内で直接メソッドを定義する方法で、もう 1 つは最初にローカル変数 (プライベート インスタンス フィールド) を定義してから匿名メソッドを定義する方法です。値を割り当てます。
クラス内でメソッドを直接定義する場合、メソッドのスコープはこのクラスであるため、このメソッドはこのクラスの外部からアクセスできません。また、クラス内のすべてのプライベート インスタンス フィールドにアクセスできます。これにより、これはプライベートであることが保証されます。インスタンスメソッド。
プライベート インスタンス メソッドを作成する 2 番目の方法は、1 番目の方法と同じ効果がありますが、2 番目の方法はより柔軟です。
class1 のコンストラクター コードが { } で囲まれていることにも注目してください。これは必須ではありませんが、コードがより明確に見えます。
このコンストラクター コードについては、次の 2 つの点について説明する必要があります。
1. コンストラクター コードは、クラス定義全体の最後に配置する必要があります。これは、その中で呼び出されるすべてのメソッドが確実に終了するようにするためです。定義されています。 JavaScript はインタープリタ言語であるため、上から順に実行されます。そのため、コンストラクターのコードが他のメソッド定義の前に配置されると、呼び出しステートメントが実行されたときに呼び出されるメソッドが見つかりません。間違ってしまいました。
2. { } によって作成されたブロックはスコープを変更しないことがすでにわかっているため、このようなコンストラクター コードでローカル変数を作成すると、実際にはクラス全体にプライベート インスタンス メンバーが作成されることになります。ローカル変数の場合は、プライベート インスタンス メソッドを定義する必要があります。たとえば、constructor() という名前を付けることができます。constructor() のプライベート インスタンス メソッドでは、ローカル変数と実行するコードを元の { で定義します。これで、クラスの最後で直接呼び出すことができます。したがって、より良い書き方は次のようになります:
コードをコピーします コードは次のとおりです:

class1 = function () {
// プライベートフィールド
var m_first = 1;
var m_second = 2;
// プライベートメソッド
functionconstructor() {

メソッド 1();
メソッド 2();
}
関数メソッド 1() {
alert(m_first);
}
var method2 = function() {
alert(
}
constructor();
var o = new class1();
// エラー
alert(o.m_first); method1();

最後に、class1 の定義で var を使用していないこともわかります。これにより、それがグローバル クラスであることを確認できます。
2.2 パブリック インスタンス メンバー
パブリック インスタンス メンバーは 2 つの方法で作成できます。まず次の例を見てみましょう:

コードをコピー コードは次のとおりです:
class2 = function() {
// プライベート フィールド
var m_first = 1;
var m_second = 2; >/ / プライベートメソッド
function method1() {
alert(m_first);
}
var method2 = function() {
alert(m_first);
// パブリックフィールド
this.first = "first";
this.next = ['s','e','c','o','n','d']; >
// パブリック メソッド
this.method1 = method2;

this.method2 = function() {
alert(this.second)}
//コンストラクター
{
method2();
}
}
// パブリック メソッド
class1.prototype.method3 = function() {


var o = new class2();
o.method2(); .method3 ();
alert(o.first);
この例では、class1 の例にいくつかの追加が加えられていることがわかりました。パブリック インスタンス フィールドとパブリック インスタンス メソッドが追加され、これらをパブリック インスタンス メンバーと呼びます。
パブリック インスタンス メンバーの作成は実際には非常に簡単であることがわかりました。1 つの方法は、値が関数以外の型の場合、パブリック インスタンス フィールドです。値が Function type の場合、それはパブリック インスタンス メソッドです。もう 1 つの方法は、className.prototype.memberName に値を割り当てることです。割り当て可能な型は this.memberName と同じです。
このメソッドを使用して定義する必要がありますか?それともプロトタイプメソッドを使用して定義する必要がありますか?
実際、それらにはそれぞれ独自の用途があり、それらの間の関係は、一方が他方より優れているというものではありません。場合によっては、パブリック インスタンス メンバーを特定の 1 つの方法でのみ定義でき、他の方法では定義できない場合があります。その理由は、実際には異なるためです。
1. プロトタイプ メソッドはクラスの外部でのみ定義される必要があります。このメソッドはクラス内でのみ定義できます。
2. クラス内にプロトタイプメソッドが定義されている場合、プライベートインスタンスのメンバーにアクセスする場合は、常に最後のオブジェクトインスタンスのプライベートインスタンスのメンバーにアクセスします。
3. プロトタイプモードで定義されたパブリックインスタンスメンバーは、クラスのプロトタイプ上に作成されたメンバーです。このメソッドで定義されるパブリック インスタンス メンバーは、クラスのインスタンス オブジェクト上に直接作成されるメンバーです。
最初の 2 つの違いに基づいて、パブリック インスタンス メソッドでプライベート インスタンスのメンバーにアクセスしたい場合は、このメソッドを使用して定義する必要があるという結論を導き出すことができます。
3 番目の違いについては、後で継承について説明するときにさらに詳しく分析します。ここで知っておく必要があるのは、この違いだけです。
パブリック インスタンスのメンバーとプライベート インスタンスのメンバーの名前が同じであることもわかります。競合は発生しないでしょうか。
もちろんそうではありません。その理由は、それらのアクセス方法が異なるためです。クラス内でパブリック インスタンスのメンバーにアクセスする場合は、このプレフィックスを使用して参照する必要があります。プライベート インスタンスのメンバーがクラス内でアクセスされる場合、このプレフィックスを使用してアクセスすることはできません。クラスの外部にアクセスする場合、クラスのインスタンス オブジェクトを介してアクセスできるのはパブリック メンバーのみであり、プライベート メンバーにはアクセスできません。
2.3 パブリック静的メンバー
パブリック静的メンバーの定義は非常に簡単です。次に例を示します。
コードをコピーコードは次のとおりです:

class3 = function() {
// プライベート フィールド
var m_first = 1;
var m_second = 2;
function method1( ) {
alert(m_first);
}
var method2 = function() {
alert(m_first);
// コンストラクター
{
method1 ();
method2();
}
}

// パブリック静的フィールド

// パブリック静的メソッド
class3.method1 = function() {
alert(class3.field1)
}

class3.method1(); >この例の class3 は class1 と同じであり、非常に似ています。違いは、class3 の外側で、class3 の静的フィールドと静的メソッドを定義していることです。
これを定義する方法は、className.memberName に値を直接割り当てることです。
ここで定義された静的フィールドと静的メソッドには、オブジェクトを作成せずに、クラス名参照を通じて直接アクセスできます。したがって、これらはパブリック静的メンバーです。
ただし、覚えておくべきことの 1 つは、パブリック静的メンバーを、それが配置されているクラス内で定義してはいけないということです。そうしないと、予期しない結果が得られます。次の例を見てみましょう:



コードをコピー

コードは次のとおりです: class4 = function() { // プライベートフィールド var m_first = 1;
var s_second = 2; 🎜>関数メソッド 1 () {
アラート (m_first);
}
var メソッド 2 = function() {
アラート (m_秒);
クラス 4.メソッド 1 = function( ) {
s_second;
}
class4.method2 = function() {
alert(s_second);
}
var o1 = new class4(); 🎜>class4.method2(); // 2
class4.method1();
class4.method2(); ); // 2
class4.method1()
class4.method2();
この例では、s_second がプライベート静的メンバーの役割を果たすことを期待していますが、出力は期待したものではありません。 s_second は実際には、プライベート静的メンバーではなく、class4 のプライベート インスタンス メンバーであることがわかります。 class4 のメソッド 1 およびメソッド 2 によってアクセスされるプライベート メンバーは、常にクラスの最後のインスタンス オブジェクト内のプライベート インスタンス メンバーです。
何が問題ですか?
問題は、new class4() を通じてオブジェクト インスタンスが作成されるたびに、class4 内のすべてのステートメントが再実行されるため、s_second がリセットされ、新しいオブジェクトのプライベート インスタンス メンバーになることです。 Class4.method1 と class4.method2 も再定義されており、この定義により変数のスコープも最後のオブジェクトに切り替わります。これは、プロトタイプを通じて作成されたパブリック インスタンス メソッドがクラス内で定義されている場合に発生するエラーと同じです。
したがって、パブリック静的メンバーが配置されているクラス内でパブリック静的メンバーを定義しないように注意してください。プロトタイプ メソッドを通じて作成されたパブリック インスタンス メソッドをクラス内で定義しないでください。
プライベート静的メンバーを定義するにはどうすればよいですか?
2.4 プライベート静的メンバー
私たちは、関数を使用して関数を作成することによってのみ、プライベート メンバー (静的メンバーであってもインスタンス メンバーであっても) を作成できることを基本概念ですでに理解しました。 )、データ隠蔽の目的を達成するには、新しいスコープを作成する必要があります。以下に採用する方法はこの点に基づくものである。
プライベート静的メンバーの実装は、新しいスコープを作成する匿名関数を作成することによって実現されます。
通常、匿名関数を使用するときは、それを変数に代入し、この変数を通じて匿名関数を参照します。この場合、無名関数を繰り返し呼び出すことも、オブジェクトをクラスとして作成することもできます。ここで、作成した匿名関数は変数に割り当てられず、作成後すぐに実行されます。または、オブジェクトとしてインスタンス化され、オブジェクトは変数に割り当てられません。この場合、関数自体またはそのインスタンスは、関数自体またはそのインスタンスになります。変換されたオブジェクトには再びアクセスできないため、その唯一の機能は、新しいスコープを作成し、その内部のすべてのローカル変数と関数を分離することです。したがって、これらのローカル変数と関数は、必要なプライベート静的メンバーになります。このすぐに実行される匿名関数、またはすぐにインスタンス化される匿名関数を静的カプセル化環境と呼びます。
まず、匿名関数を直接呼び出してプライベート静的メンバーを持つクラスを作成する例を見てみましょう:
コードをコピーコードは次のとおりです:

class5 = (function() {
// プライベート静的フィールド
var s_first = 1;
var s_second = 2;

// プライベート静的メソッド
function s_method1() {
s_first ;
}
var s_second = 2;

functionconstructor() {
// プライベート フィールド
var m_first = 1;
新しい JavaScript オブジェクト指向トレーニング (2)
var m_second = 2;

// プライベート メソッド
function method1() {
alert( m_first);
}
var method2 = function() {
alert(m_second);
}

// パブリックフィールド
this.first = "first";
this.second = ['s','e','c','o','n','d'];

// パブリック メソッド
this.method1 = function() {
s_second--;
}

this.method2 = function() {
alert(this.second);

/ / コンストラクター
{
s_method1();
this.method1();
}
}
// パブリック静的メソッド
constructor.method1 = function() {
s_first ;
alert(s_first);
constructor.method2 = function() {
alert
}

return コンストラクター; )();

var o1 = 新しいクラス 5.method1();
o1.method2(); = new class5();
class5.method2();
(function(); 🎜>...
関数コンストラクター () {
...
}
戻りコンストラクター


静的カプセル化環境を作成するには、実際のクラスがこの環境で定義され、最後に、return ステートメントを通じて最終クラスがグローバル変数 class5 に返され、その後、class5 A クラスを通じてこのバンドを参照できます。静的プライベートメンバーを使用します。
プライベート静的メンバーとプライベート インスタンス メンバーを区別するために、プライベート静的メンバーの前に s_ 接頭辞を使用し、プライベート インスタンス メンバーの前に m_ 接頭辞を使用します。これにより、名前の重複が回避されるため、プライベート オブジェクトは常に使用できます。静的メンバーでアクセスできます。
ただし、この命名方法は必須ではなく、推奨されるだけです。名前が重複している場合、プライベート静的メンバーは、クラス コンストラクターとインスタンス メソッドでアクセスできます。これはプライベート インスタンス メンバーであり、静的メソッド (パブリック静的メソッドでもプライベート静的メソッドでも) でアクセスされるものはすべてプライベート静的メンバーです。
クラス外および静的カプセル化環境でプロトタイプを通じて定義されたパブリック インスタンス メソッドは、プライベート静的メンバーにアクセスします。
静的カプセル化環境の外部で定義されたパブリック静的メソッドおよびプロトタイプを通じて定義されたパブリック インスタンス メソッドは、プライベート静的メンバーに直接アクセスできません。
匿名関数を直接インスタンス化してプライベート静的メンバーを持つクラスを作成する別の方法は、上記の例とよく似ています:
コードをコピー コードは次のとおりです:

new function() {
// プライベート静的フィールド
var s_first = 1;
var s_second = 2; 🎜>// プライベート静的メソッド
function s_method1() {
s_first ;
}
var s_second = 2;

class6 = function() {
// プライベートフィールド
var m_first = 1;
var m_second = 2;

// プライベートメソッド
function method1() {
alert(m_first)
var method2 = function() {
alert(m_second);
}

// パブリックフィールド
this.first = "first";
this.second = ['s ','e','c','o','n','d'];

// パブリック メソッド
this.method1 = function() {
s_second-- ;
}

this.method2 = function() {
alert(this.second);

// コンストラクター
{
s_method1 ();
this.method1();
}
}
// パブリック静的メソッド
class6.method1 = function() {
s_first; );
}
class6.method2 = function() {
alert(s_second)
}
}; >クラス6.メソッド1();
クラス6.メソッド2();
クラス6.メソッド1();
o2.method2();


この例の結果は、最初のメソッドで作成した例と同じです。ただその静的カプセル化環境は次のようになっています:
new function() {
...
};
ここでは、関数には戻り値がなく、class5 の定義が直接含まれています。静的カプセル化環境は、var で定義されていない変数に値を割り当てることによって内部的に実装されます。
もちろん、関数の戻り値を定義せずに
(function() {
...
})();
を使用することもできます。 var で定義されていない変数に値を代入することで、プライベート静的メンバーを持つクラスの定義を実装します。
ここでは 2 つのメソッドは同等です。
2.5 静的クラス
いわゆる静的クラスは、インスタンス化できず、静的メンバーのみを含むクラスです。
JavaScript では、匿名関数オブジェクトを直接インスタンス化することで静的クラスを実装できます。例:




コードをコピー


コードは次のとおりです:


class7 = new function() {
// プライベート静的フィールド
var s_first = 1; var s_second = 2; // プライベート静的メソッド function method1() { alert(s_first); 🎜>} // public static メソッド this.method1 = function() {
method1();
alert(s_second);
}
}
class7。


class7 は実際にはオブジェクトですが、このオブジェクトは匿名クラスに属していることがわかります。class7 オブジェクトが作成された後は、このクラスは使用できなくなります。 Class7 は関数ではないため、クラスとしてインスタンス化できません。したがって、ここでは静的クラスに相当します。
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート