ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScriptオブジェクト指向プログラミングの基礎_基礎知識
オブジェクト指向を再理解する
JavaScript が完全なオブジェクト指向言語であることを説明するには、まずオブジェクト指向の概念から始めて、オブジェクト指向のいくつかの概念について説明する必要があります。
これら 3 つの点に基づくと、C はクラスのカプセル化、継承、ポリモーフィズムを実装しているものの、非オブジェクトのグローバル関数と変数が存在するため、半オブジェクト指向かつ半手続き型言語です。 Java と C# は完全なオブジェクト指向言語であり、オブジェクトなしでは存在できないように関数と変数をクラスの形式で編成します。しかし、ここでは関数自体がプロセスであり、特定のクラスにアタッチされているだけです。
しかし、オブジェクト指向は単なる概念またはプログラミングのアイデアであり、その存在を特定の言語に依存すべきではありません。たとえば、Java はオブジェクト指向の考え方を使用して言語を構築し、クラス、継承、派生、ポリモーフィズム、インターフェイスなどのメカニズムを実装します。ただし、これらのメカニズムはオブジェクト指向プログラミングを実装するための手段にすぎず、必須ではありません。言い換えれば、言語は、独自の特性に基づいてオブジェクト指向を実装するための適切な方法を選択できます。したがって、ほとんどのプログラマは、最初に Java や C などの高レベルのコンパイル言語を学習または使用するため (Java はセミコンパイルおよびセミインタープリタですが、一般的にはコンパイル言語として説明されます)、「クラス」という用語を先入観で受け入れます。オブジェクト指向の実装方法であるため、スクリプト言語を学習する際には、その言語がオブジェクト指向言語であるかどうか、またはオブジェクト指向の特性を備えているかどうかを判断するために、クラスベースのオブジェクト指向言語の概念を使用するのが通例です。これは、プログラマーが JavaScript を深く学習して習得することを妨げる重要な理由の 1 つでもあります。
実際、JavaScript 言語はプロトタイプと呼ばれるメソッドを通じてオブジェクト指向プログラミングを実装します。客観的な世界を構築する 2 つの方法、クラスベースのオブジェクト指向とプロトタイプベースのオブジェクト指向の違いについて説明します。
クラスベースのオブジェクト指向アプローチとプロトタイプベースのオブジェクト指向アプローチの比較
クラスベースのオブジェクト指向アプローチでは、オブジェクトはクラスに基づいて生成されます。プロトタイプベースのオブジェクト指向アプローチでは、オブジェクトはコンストラクターとプロトタイプを使用して構築されます。 2 つの認識方法の違いを説明するために、客観的な世界の例を挙げてください。たとえば、工場で自動車を製造する場合、作業員は設計図を参照する必要があり、その設計によって自動車の製造方法が規定されます。ここでの設計図は言語の授業のようなもので、車はこの授業に基づいて作られますが、作業者や機械(建設業者に相当)はエンジンやタイヤ、ハンドル(部品の各属性に相当)などのさまざまな部品を使用します。プロトタイプ) が車を組み立てます。
実際、2 つの方法のうちどちらがオブジェクト指向のアイデアをより完全に表現しているかについては、まだ議論があります。しかし、著者は、次の理由から、プロトタイプ オブジェクト指向はより徹底したオブジェクト指向のアプローチであると信じています。
まず第一に、客観的な世界におけるオブジェクトの作成は他の物理的なオブジェクトの構築の結果であり、抽象的な「図面」からは「車」を生み出すことはできません。言い換えれば、クラスは実体ではなく抽象的な概念です。オブジェクトの作成はエンティティの作成です。
次に、すべてがオブジェクトであるというオブジェクト指向の最も基本的なルールに従って、クラス自体はオブジェクトではありませんが、プロトタイプ メソッドのコンストラクターとプロトタイプ自体は、構築されたオブジェクトによって別のオブジェクトになります。
第三に、クラスベースのオブジェクト指向言語では、オブジェクトの状態はオブジェクトのインスタンスが保持し、オブジェクトの動作メソッドはオブジェクトを宣言するクラスが保持し、構造とメソッドのみを継承できます。 ; プロトタイプのオブジェクト指向言語では、オブジェクトの動作とステータスはオブジェクト自体に属し、一緒に継承できます (参照リソース)。これは客観的な現実に近いものです。
最後に、Java などのクラスベースのオブジェクト指向言語では、手続き型言語でグローバル関数や変数を使用できない不便さを補うために、クラス内で静的プロパティや静的メソッドを宣言できます。実際、すべてがオブジェクトであるため、客観的な世界にはいわゆる静的な概念は存在しません。プロトタイプのオブジェクト指向言語では、組み込みオブジェクト、グローバル オブジェクト、メソッド、またはプロパティを除いて、存在することは許可されず、静的な概念は存在しません。すべての言語要素 (プリミティブ) は、その存在のためにオブジェクトに依存する必要があります。ただし、関数型言語の特性により、言語要素が依存するオブジェクトは実行時コンテキストの変化に応じて変化し、特に this ポインターの変化に反映されます。この性質は、「すべてのものは何かに属しており、宇宙はすべてのものの生存の基盤である」という自然観に近いものです。
JavaScript オブジェクト指向の基礎知識
オブジェクトを作成する簡単な方法は次のとおりです:
function myObject() { }; JavaScript 中创建对象的方法一般来说有两种:函数构造法和字面量法,上面这种属函数构造法。下面是一个字面量法的例子: var myObject = { };
オブジェクトが 1 つだけ必要で、そのオブジェクトの他のインスタンスが必要ない場合は、リテラル メソッドを使用することをお勧めします。オブジェクトの複数のインスタンスが必要な場合は、関数コンストラクターをお勧めします。
プロパティとメソッドを定義する
関数構築方法:
function myObject() { this.iAm = 'an object'; this.whatAmI = function() { console.log('I am ' + this.iAm); }; };
リテラルメソッド:
var myObject = { iAm : 'an object', whatAmI : function() { console.log('I am ' + this.iAm); } };
上記の 2 つのメソッドで作成されたオブジェクトには、「iAm」という名前のプロパティと「whatAmI」という名前のメソッドがあります。プロパティはオブジェクト内の変数であり、メソッドはオブジェクト内の関数です。
属性を取得してメソッドを呼び出す方法:
var w = myObject.iAm; myObject.whatAmI();
メソッドを呼び出すときは、メソッドの後にかっこを追加する必要があります。かっこを追加しない場合は、メソッドへの参照が返されるだけです。
オブジェクトを作成する 2 つの方法の違い
リテラル メソッドで作成されたオブジェクトの場合、オブジェクトの参照を使用してそのプロパティまたはメソッドを直接呼び出すことができます。
myObject.whatAmI();
関数コンストラクターの場合、そのプロパティまたはメソッドを呼び出す前に、オブジェクトのインスタンスを作成する必要があります。
var myNewObject = new myObject(); myNewObject.whatAmI();
コンストラクターを使用する
ここで、前の関数構築方法に戻りましょう:
function myObject() { this.iAm = 'an object'; this.whatAmI = function() { console.log('I am ' + this.iAm); }; };
実際は関数のように見えますが、関数なのでパラメータを渡すことはできますか?コードを少し変更します:
function myObject(what) { this.iAm = what; this.whatAmI = function(language) { console.log('I am ' + this.iAm + ' of the ' + language + ' language'); }; };
次に、オブジェクトをインスタンス化し、パラメーターを渡します。
var myNewObject = new myObject('an object'); myNewObject.whatAmI('JavaScript');
プログラムの最終出力は、「私は JavaScript 言語のオブジェクトです」です。
オブジェクトを作成するには 2 つの方法がありますが、どちらを使用すればよいですか?
リテラル メソッドの場合、インスタンス化が必要ないため、オブジェクトの値が変更されると、そのオブジェクトの値は永続的に変更され、その他のアクセスは変更された値になります。関数コンストラクターの場合、値を変更すると、そのインスタンスの値が変更され、N 個のオブジェクトをインスタンス化でき、各オブジェクトは相互に干渉することなく独自の異なる値を持つことができます。次のコード スニペットを比較してください。
まずリテラルメソッドを見てみましょう:
var myObjectLiteral = { myProperty : 'this is a property' }; console.log(myObjectLiteral.myProperty); // log 'this is a property' myObjectLiteral.myProperty = 'this is a new property'; console.log(myObjectLiteral.myProperty); // log 'this is a new property'
このオブジェクトを指すように新しい変数が作成された場合でも、結果は同じです:
var myObjectLiteral = { myProperty : 'this is a property' }; console.log(myObjectLiteral.myProperty); // log 'this is a property' var sameObject = myObjectLiteral; myObjectLiteral.myProperty = 'this is a new property'; console.log(sameObject.myProperty); // log 'this is a new property'
関数の構築方法をもう一度見てください:
// 用函数构造法 var myObjectConstructor = function() { this.myProperty = 'this is a property' }; // 实例化一个对象 var constructorOne = new myObjectConstructor(); // 实例化第二个对象 var constructorTwo = new myObjectConstructor(); // 输出 console.log(constructorOne.myProperty); // log 'this is a property' // 输出 console.log(constructorTwo.myProperty); // log 'this is a property' 和预期一样,两个对象的属性值是一样的。如果修个其中一个对象的值呢? // 用函数构造法 var myObjectConstructor = function() { this.myProperty = 'this is a property'; }; // 实例化一个对象 var constructorOne = new myObjectConstructor(); // 修改对象的属性 constructorOne.myProperty = 'this is a new property'; // 实例化第二个对象 var constructorTwo = new myObjectConstructor(); // 输出 alert(constructorOne.myProperty); // log 'this is a new property' // 输出 alert(constructorTwo.myProperty); // log 'this is a property'
ご覧のとおり、関数コンストラクターを使用してインスタンス化されたさまざまなオブジェクトは互いに独立しており、それぞれが異なる値を持つことができます。したがって、どの方法でオブジェクトを作成するかは、実際の状況によって異なります。