ホームページ > 記事 > ウェブフロントエンド > JavaScript オブジェクト指向プログラミング (1): カプセル化
JavaScript はオブジェクトベースの言語であり、遭遇するほとんどすべてがオブジェクトです。ただし、構文にクラスがないため、真のオブジェクト指向プログラミング (OOP) 言語ではありません。
では、「プロパティ」と「メソッド」をオブジェクトにカプセル化したい場合、あるいはプロトタイプオブジェクトからインスタンスオブジェクトを生成したい場合は、どうすればよいでしょうか?
1. インスタンス オブジェクトを生成する元のモード
猫を「名前」と「色」の 2 つの属性を持つオブジェクトとみなします。
var Cat = { name : '', color : '' }
次に、このプロトタイプ オブジェクトの仕様 (スキーマ) に基づいて 2 つのインスタンス オブジェクトを生成する必要があります。
var cat1 = {}; // 创建一个空对象 cat1.name = "大毛"; // 按照原型对象的属性赋值 cat1.color = "黄色"; var cat2 = {}; cat2.name = "二毛"; cat2.color = "黑色";
さて、これは 2 つのプロパティを 1 つのオブジェクトにカプセル化する、最も単純なカプセル化です。ただし、この書き方には 2 つの欠点があります。1 つは、より多くのインスタンスが生成される場合、作成が非常に面倒になることです。2 つ目は、インスタンスとプロトタイプ間の接続を確認する方法がありません。
2. オリジナルモデルの改良
コードの重複の問題を解決する関数を書くことができます。
function Cat(name,color) { return { name:name, color:color } }
インスタンス オブジェクトの生成は、関数を呼び出すことと同じです:
var cat1 = Cat("大毛","黄色"); var cat2 = Cat("二毛","黑色");
このメソッドの問題は、依然として cat1 と cat2 の間に本質的な接続がなく、それらが同じプロトタイプ オブジェクトのインスタンスであることを反映できないことです。
3. コンストラクター パターン
プロトタイプ オブジェクトからインスタンスを生成する問題を解決するために、JavaScript はコンストラクター パターンを提供します。
いわゆる「コンストラクター」は実際には通常の関数ですが、this変数は内部で使用されます。コンストラクターで new 演算子を使用するとインスタンスが生成され、this 変数はインスタンス オブジェクトにバインドされます。
たとえば、cat のプロトタイプ オブジェクトは次のように記述できるようになり、
function Cat(name,color){ this.name=name; this.color=color; }
インスタンス オブジェクトを生成できるようになりました。
var cat1 = new Cat("大毛","黄色"); var cat2 = new Cat("二毛","黑色"); alert(cat1.name); // 大毛 alert(cat1.color); // 黄色
この時点で、cat1 と cat2 には、コンストラクターを指すコンストラクター属性が自動的に含まれます。
alert(cat1.constructor == Cat); //true alert(cat2.constructor == Cat); //true
Javascript は、プロトタイプ オブジェクトとインスタンス オブジェクトの間の関係を検証するための instanceof 演算子も提供します。
alert(cat1 instanceof Cat); //true alert(cat2 instanceof Cat); //true
4. コンストラクターパターンの問題点
コンストラクターメソッドは使いやすいですが、メモリを無駄に消費するという問題があります。
ご覧ください。変更されていない属性タイプ (type) を Cat オブジェクトに追加し、メソッド Eat (eat) を追加します。すると、プロトタイプ オブジェクト Cat は次のようになります:
function Cat(name,color){ this.name = name; this.color = color; this.type = "猫科动物"; this.eat = function(){alert("吃老鼠");}; }
同じメソッドを使用してインスタンスを生成します:
var cat1 = new Cat("大毛","黄色"); var cat2 = new Cat ("二毛","黑色"); alert(cat1.type); // 猫科动物 cat1.eat(); // 吃老鼠
表面的には問題がないように見えますが、実際には、そうすることには大きな欠点があります。つまり、インスタンス オブジェクトごとに、type 属性と Eat() メソッドの内容はまったく同じになります。インスタンスが生成されるたびに、繰り返しの内容のためにより多くのメモリを占有する必要があります。これは環境に優しくも効率的でもありません。
alert(cat1.eat == cat2.eat); //false
type 属性と Eat() メソッドをメモリ内で 1 回だけ生成し、その後すべてのインスタンスがそのメモリ アドレスを指すようにすることはできますか?答えは「はい」です。
5. プロトタイプ モード
JavaScript では、各コンストラクターが別のオブジェクトを指すプロトタイプ属性を持つことを規定しています。このオブジェクトのすべてのプロパティとメソッドは、コンストラクターのインスタンスによって継承されます。
これは、これらの不変のプロパティとメソッドをプロトタイプ オブジェクトに直接定義できることを意味します。
function Cat(name,color){ this.name = name; this.color = color; } Cat.prototype.type = "猫科动物"; Cat.prototype.eat = function(){alert("吃老鼠")};
次に、インスタンスを生成します。
var cat1 = new Cat("大毛","黄色"); var cat2 = new Cat("二毛","黑色"); alert(cat1.type); // 猫科动物 cat1.eat(); // 吃老鼠
このとき、すべてのインスタンスの type 属性と Eat() メソッドは実際には同じメモリ アドレスとなり、プロトタイプ オブジェクトを指すため、動作効率が向上します。
alert(cat1.eat == cat2.eat); //true
6. プロトタイプモードの検証方法
プロトタイプ属性と連携するために、Javascript はそれを使用するのに役立ついくつかの補助メソッドを定義します。 ,
6.1 isPrototypeOf()
このメソッドは、特定のプロトタイプ オブジェクトとインスタンスの間の関係を決定するために使用されます。
alert(Cat.prototype.isPrototypeOf(cat1)); //true alert(Cat.prototype.isPrototypeOf(cat2)); //true
6.2 hasOwnProperty()
各インスタンス オブジェクトには hasOwnProperty() メソッドがあり、特定のプロパティがローカル プロパティであるか、プロトタイプ オブジェクトから継承されたプロパティであるかを判断するために使用されます。
alert(cat1.hasOwnProperty("name")); // true alert(cat1.hasOwnProperty("type")); // false
6.3 in 演算子
in 演算子は、インスタンスに特定の属性が含まれているかどうか、それがローカル属性であるかどうかを判断するために使用できます。
alert("name" in cat1); // true alert("type" in cat1); // true
in 演算子を使用して、オブジェクトのすべてのプロパティを走査することもできます。
りー