JavaScript定義類と対象に関するいくつかの方法

5902 ワード

この例を見てもいいです.
 
  
var a = 'global';
(function () {
alert(a);
var a = 'local';
})();
まずこの例を見て、出力結果は何ですか?global?それとも「local」ですか?実は全部ではないです.出力はundefinedです.迷わないでください.
実は簡単です.JavaScriptの運行メカニズムを見れば分かります.私たちはこの現象を「前声明」と見なしてもいいです.でも、ちょっと深く追究すれば、もっとよく分かります.
ここでは、実際にはオブジェクト属性バインディング機構に関連しています.すべてのJavaScript関数は対象です.関数で宣言した変数は、このオブジェクトの「類似の属性」とみなすことができます.オブジェクト属性のバインディングは、言語に「早バインディング」と「後バインディング」の区別があります.
【早期バインディング】
は、オブジェクトを具体化する前に属性と方法を定義することです.解析プログラムの場合は事前にマシンコードに変換できます.C+++,javaなどの通常の強いタイプの言語は、早い結合機構である.JavaScriptは強いタイプの言語ではありません.それは「遅いバインディング」機構を使用しています.
【バインディング】
プログラムを実行する前に、オブジェクトの種類を確認する必要がなく、オブジェクトがサポートされているかどうかを確認すればいいということです.バインディング前にオブジェクトに対して任意の罰則を受けずに大量の動作を実行することができます.
上記のコードで発生した「前声明」現象は、「後結合」機構で説明できます.関数の作用領域では、すべての変数が「遅いバインディング」されます.つまり声明はトップクラスです.上のコードは下のコードと一致します.
 
  
var a = 'global';
(function () {
var a;
alert(a);
a = 'local';
})();
alert(a)前にaに対してだけ宣言しました.結果は予想できます.
RT:本文で言いたいのは、JavaScriptにおいて、私が知っているいくつかの定義類と対象の方法です.
【直接量方式】
直接量を使ってオブジェクトを構築するのが基本的な方式ですが、欠点もたくさんあります.
 
  
var Obj = new Object;
Obj.name = 'sun';
Obj.showName = function() {
alert('this.name');
}
オブジェクトObjを構築しました.これはname属性を持っています.もし私たちが同じようなオブジェクトを構築するなら?もう一度繰り返しますか?
NO特定のタイプのオブジェクトを返す工場関数で実現できます.工場のように、私たちが求める特定のタイプの結果を流します.
【工場方式】
 
  
function createObj(name) {
var tempObj = new Object;
tempObj.name = name;
tempObj.showName = function () {
alert(this.name);
};
return tempObj;
}
var obj1 = createObj('obj_one');
var obj2 = createObj('obj_two');
この工場関数は多くの人が彼を対象としない形です.一部の原因は、演算子newを用いて構築されたものほど正規ではないという意味である.もう一つ大きな理由は、この工場が出力するたびに新しい関数showName()を作成します.つまり、対象ごとに異なるバージョンを持っていますが、実際には同じ関数を共有しています.
ショーNameを工場の関数外で定義し、属性を通じてこの方法を指す人がいます.この問題を避けることができます.
 
  
function showName () {
alert(this.name);
}
function createObj(name) {
var tempObj = new Object;
tempObj.name = name;
tempObj.showName = showName;
return tempObj;
}
var obj1 = createObj('obj_one');
var obj2 = createObj('obj_two');
残念なことに、この方法はshowName()という関数を対象としないように見せる方法です.
【構造関数方式】
この方式は上の工場関数の最初の問題、すなわちnew演算子の問題を解決するためです.しかし、第二の問題は依然として解決できません.見てみましょう
 
  
function Obj(name) {
this.name = name;
this.showName = function () {
alert(this.name);
}
}
var obj1 = new Obj('obj_one');
var obj2 = new Obj('obj_two');
この利点は、new演算子が実行されるときに自動的にオブジェクトを作成し、thisを通じてのみこのオブジェクトにアクセスすることができるからです.したがって、私たちは直接にこのオブジェクトに対して、thisを通じて値を割り当てることができます.また、リセットしなくてもいいです.thisはデフォルトのコンストラクタの戻り値を指しています.
また、newというキーワードを使って、私たちが欲しい対象を作成したほうが、より「正式」に感じられますか?
残念ながら、これはまだ解決できません.方法関数を繰り返し生成する問題は工場関数と同じです.
【原型方式】
この方式は上記の方式と比較して,方法関数が多重生成される問題を解決する大きな利点がある.対象のプロトタイプの属性を利用しています.原型に依存してオブジェクトのインスタンスを書き換えることができます.
 
  
var Obj = function () {}
Obj.prototype.name = 'me';
Obj.prototype.showName = function () {
alert(this.name);
}
var obj1 = new Obj();
var obj2 = new Obj();
プロトタイプに依存して構造関数を書き換えたが、属性も方法もプロトタイプ参照によって新規オブジェクトに与えられたので、一回だけ作成されます.残念なことに、この方法には二つの致命的な問題があります.
1です.オブジェクトを構築する時には、オブジェクトが作成されたときに属性値を書き込むことができませんでした.プロトタイプは構造関数の作用領域の外にありますので、パラメータを伝達することで、オブジェクトが作成されたときに属性値を書き込むことができませんでした.オブジェクトの作成が完了したら、値を書き換えます.
2です.致命的な問題は、属性がオブジェクトに向けられている場合、このオブジェクトは複数のインスタンスで共有されます.以下のコードを考慮します.
 
  
var Obj = function () {}
Obj.prototype.name = 'me';
Obj.prototype.flag = new Array('A', 'B');
Obj.prototype.showName = function () {
alert(this.name);
}
var obj1 = new Obj();
var obj2 = new Obj();
obj1.flag.push('C');
alert(obj1.flag); // A,B,C
alert(obj2.flag); //A,B,C
はい、flags属性がオブジェクトに向けられている場合、例のObj 1とObj 2は共有されています.たとえ私たちがObj 1のflags属性を変更しただけでも、その変更はインスタンスObj 2で見られます.
この問題に対して、「構造関数方式」と「原型方式」を結びつけて、お互いに補完するべきかどうかを考えざるを得ません.
【構造関数と原型の混合方式】
属性をコンストラクタ方式で作成させます.方法はプロトタイプで作成すればいいです.
 
  
var Obj = function (name) {
this.name = name;
this.flag = new Array('A', 'B');
}
Obj.prototype = {
showName : function () {
alert(this.name);
}
}
var obj1 = new Obj();
var obj2 = new Obj();
obj1.flag.push('C');
alert(obj1.flag); // A,B,C
alert(obj2.flag); //A,B
この方法はプロトタイプとコンストラクタの利点を効果的に結合しており、現在最も多く使われており、副作用が最も少ない方法でもある.
しかし、いくつかの完璧を追求する人はまだ満足していません.視覚的にはまだ彼らの要求に達していません.原型を通して方法を作る過程は視覚的にはあまり具体的な方法とは思えないからです.(特に伝統的なOOP言語の開発者にとって).
だから、私達は原型を活動させて、彼も構造関数に参加させて、この構造関数を視覚的に統一させることができます.この一連の過程は一つの判断で完成できます.
 
  
var Obj = function (name) {
this.name = name;
this.flag = new Array('A', 'B');
if (typeof Obj._init == 'undefined') {
Obj.prototype = {
showName : function () {
alert(this.name);
}
};
Obj._init = true;
}
}
以上のようにinitはマークとして原型の作成方法を判断します.もしそうなら、もう実行しません.このように本質的には何の変化もありません.方法は原型を通して作成されます.唯一の違いはこの構造関数が「江山統一」に見えます.
しかし、このようなダイナミックプロトタイプの方式は問題があります.最初のオブジェクトを作成するときは、プロトタイプは対象が実用化される前に来ていないものや建設されていますので、全くアクセスできません.最初のオブジェクトはプロトタイプにアクセスできません.また、この方法はサブクラスの継承にも問題があります.
解決策については、次の文で説明します.
実は使いやすいということは、個人的にはこの判断をする必要がないと思います..ふふん^^_^