JavaScript でのカプセル化
カプセル化とは、単に外部の世界がオブジェクトの共通の変数と関数にのみアクセスでき、詳細とデータが隠蔽されることを意味します。
js でオブジェクトを作成するには 3 つの方法があります。つまり、ドアを開く方法、命名規則を使用してプライベート変数を区別する方法、およびクロージャーを使用して実際のプライベート変数を作成する方法です。
1. オープンドアはオブジェクトを実現するための最も基本的な方法であり、すべてのメソッドと変数は共通であり、外部からアクセスできます。
var Book = function(name){ if(this.check(name)){ console.log("error"); throw new Error("name null"); } this.name = name; } Book.prototype = { check:function(name){ if(!name){ return true; } }, getName:function(){ return this.name; } } var book = new Book("哈哈"); //output:哈哈 哈哈 console.log(book.name,book.getName());
この例は、オープンドアの典型的な例であり、外部の世界がオブジェクトのプロパティとメソッドに直接アクセスできます。プロパティと変数が「this」で作成されていることがわかります。
2. プライベート変数を区別するために命名規則を使用します。プログラマが _getName() メソッドを使用する場合、このメソッドはオープンドア メソッドの前に「_」を付けるだけで区別されます。メソッドを呼び出すことはまだ防ぐことができませんが、実際には変数を隠しているわけではありません。
3. クロージャは実際のプライベート変数を作成します。このメソッドは、js 内の関数のみがスコープを持ち、コンストラクターのスコープ内で関連する変数を定義するという事実を利用し、定義ドメインのスコープ内のすべての関数からこれらの変数にアクセスできます。
var Book2 = function(name){ if(check(name)){ console.log("error"); throw new Error("name null"); } name = name; function check(name){ if(!name){ return true; } } this.getName = function(){ return name; } } Book2.prototype = { display:function(){ //无法直接访问name return "display:"+this.getName(); } } var book2 = new Book2("哈哈"); //output:undefined "哈哈" "display:哈哈" console.log(book2.name,book2.getName(),book2.display());
ご覧のとおり、この例では、name に直接アクセスすると、未定義の結果が返されます。この例とオープンドア型の違いは、「this」を使用して作成されているのに対し、この例では var を使用して変数を作成していることがわかります。そのため、name 関数と check 関数はコンストラクター内でのみ作成でき、関数のスコープ内でアクセスされ、外部から直接アクセスすることはできません。
この方法は最初の 2 つの方法の問題を解決しますが、いくつかの欠点もあります。オープンドア オブジェクト作成モードでは、すべてのメソッドがプロトタイプ オブジェクト内に作成されるため、オブジェクト インスタンスがいくつ生成されても、これらのメソッドのコピーが 1 つだけメモリ内に存在します。このメソッドでは、生成される各新しいオブジェクトが Create になります。プライベート変数とメソッドの新しいコピー。より多くのメモリを消費します。
JavaScript の継承
基本クラスの予約:
var Book = function(name){ if(this.check(name)){ console.log("error"); throw new Error("name null"); } this.name = name; } Book.prototype = { check:function(name){ if(!name){ return true; } }, getName:function(){ return this.name; } }
継承メソッド:
function extend(subClz,superClz){ var F = function(){} F.prototype = superClz.prototype; subClz.prototype = new F(); subClz.prototype.constructor = subClz; subClz.superClass = superClz.prototype; if(superClz.prototype.constructor == Object.prototype.constructor){ superClz.prototype.constructor = superClz; }
空の関数 F をブリッジとして使用すると、親クラスを直接インスタンス化するときに親クラスのコンストラクターを呼び出す追加のオーバーヘッドを回避できます。また、親クラスのコンストラクターにパラメーターがある場合は、subClass.prototype = new superClass() を通じて直接実装する必要があります。 ; 親クラスのコンストラクターの呼び出しと、プロトタイプ チェーンを介した継承は許可されません。
subClz.superClass = superClz.prototype; if(superClz.prototype.constructor == Object.prototype.constructor){ superClz.prototype.constructor = superClz; }
これら 3 つの文を追加すると、サブクラスが親クラスを継承して Book.call(this, name) を記述するのを防ぐことができ、代わりに単に ArtBook.superClass.Constructor.call(this, name) と記述することができます。
そして、サブクラスが親クラスのメソッドをオーバーライドすると、親クラスのメソッドを呼び出すことができます:
ArtBook.prototype.getName = functiion(){ return ArtBook.superClass.getName.call(this) + "!!!"; }
ArtBook サブクラス:
var ArtBook = function(name,price){ ArtBook.superClass.Constructor.call(this,name); this.price = price; } extend(ArtBook,Book); ArtBook.prototype.getPrice = function(){ return this.price; } ArtBook.prototype.getName = function(){ return ArtBook.superClass.getName.call(this)+"!!!"; }