1. JavaScript の型 ドキュメント。n('
--------
JavaScript はオブジェクトベースの言語ですが、オブジェクト (Object) は JavaScript の最初の型ではありません。 JS
は、最初のタイプとして Function を持つ言語です。これは、JS の関数が高級言語の関数のさまざまな特徴を備えているだけでなく、JS ではオブジェクトも関数によって実装されるためです。 ——この点については、
の「構築と破壊」の項で詳しく説明されています。
JS は弱く型指定されており、その組み込み型はシンプルかつ明確です:
----------------------- - -----------------------------
未定義 : 未定義
数値 : 数値
ブール値 : ブール値値
文字列: 文字列
関数: 関数
オブジェクト: オブジェクト
1) 未定義の型
=============== = =======
IE5 以前では、直接代入と typeof() を除き、未定義に対するその他の操作は
例外を引き起こします。変数が未定義かどうかを知る必要がある場合は、typeof() メソッドのみを使用できます:
ただし、IE5.5 以降では、未定義は実装されたシステム予約語です。したがって、
の比較と演算には undefined を使用できます。値が未定義かどうかを確認する簡単な方法は次のとおりです。
したがって、コア コードを IE5 以前のバージョンと (部分的に) 互換にするために、次のコード行があります。 Romo コアユニットが未定義の値を
「宣言」する:
//---------------------------- ---- -----------------------
// Qomolangma のコード (JSEnhance.js 内)
//----- ----- -------------------------------------- --
var unknown = void null;
このコード行には、void ステートメントの適用について説明する必要があるもう 1 つの点があります。 void は、「次のステートメントを実行し、
戻り値を無視する」ことを意味します。したがって、実行可能な「単一の」ステートメントはどれも void の後に出現できます。実行結果は<script> <BR>var v; <BR>if (typeof(v) == 'undefined') { <BR>// ... <BR>} <BR></script>未定義です。もちろん、必要に応じて、以下のコードのいずれかを使用して「未定義を定義」することもできます。
//------------------------------------------ ------------
// 1. 匿名の空関数を使用して
//------------ -- を返す、より複雑なメソッド---------------------------------------
var unknown = function (){}();
//--------------------------------- -- ------------------------
// 2. コードは単純ですが、理解するのは簡単ではありません
//---- -------------------------------------------------- - --
var unknown = void 0;
void も関数のように使用できるため、void(0) も有効です。場合によっては、一部の複雑なステートメントでは、
形式の void キーワードを使用できず、void 関数形式を使用する必要がある場合があります。例:
//------------------------------------------ ------ ----------------
// void() 形式の複雑な式を使用する必要があります
//------ ---------- --------------------------------------
void(i=1) ; // または次のステートメント:
2)。 =========== =======
JavaScript は常に浮動小数点数を扱うため、Delphi の MaxInt のような定数はありません。代わりに、次のような 2 つの定数値定義があります。
:
Number.MAX_VALUE : JScript が表現できる最大の数値を返します。東経 1.79 308 にほぼ等しい。
Number.MIN_VALUE: JScript で 0 に最も近い数値を返します。 2.22E-308とほぼ同等。
整数型がないため、CSS および DOM プロパティの一部の操作では、値が整数 2 であると予想される場合、
文字列 "2.0" または同様の状況が返されることがあります。この点に関しては。この場合、グローバル オブジェクト (Gobal) の parseInt() メソッドに
を使用する必要がある場合があります。
グローバル オブジェクト (Gobal) には、数値型の演算に関連する 2 つのプロパティがあります。
NaN: 算術式の結果が数値でない場合、NaN 値が返されます。
無限: MAX_VALUE より大きい数値。
値が NaN である場合は、グローバル オブジェクト (Gobal) の isNaN() メソッドを通じて検出できます。ただし、2 つの NaN
値は互いに等しくありません。例:
//----------------------------------------------------- ------- ---------------
//NaN の演算と検出
//-------------- ------ -------------------------------------
var
v1 = 10 * 'a ';
v2 = 10 * 'a';
document.writeln(isNaN(v2)); writeln(v1 == v2 );
グローバル オブジェクト (Gobal) の Infinity は、最大値 (Number.MAX_VALUE) より大きい値を表します。 JS では、
は数学演算における正の無限大と同じ値を持ちます。 ——いくつかの実用的な手法では、
配列シーケンスの境界検出を行うために使用することもできます。
Infinity は Number オブジェクトで POSITIVE_INFINITY として定義されます。さらに、負の無限大も Number で定義されます:
Number.POSITIVE_INFINITY: 最大の正の数 (Number.MAX_VALUE) より大きい値。正の無限大。
Number.NEGATIVE_INFINITY : 最小の負の数 (-Number.MAX_VALUE) より小さい値。負の無限大。
NaN とは異なり、2 つの Infinity (または -Infinity) は互いに等しいです。例:
//----------------------------------------------------- ------- ---------------
//無限演算と検出
//-------------- ------ -------------------------------------
var
v1 = 数値.MAX_VALUE * 2;
ドキュメント.writeln(v1);
ドキュメント.writeln(v1 == v2) );
Global の数値型に関連するその他のメソッドは次のとおりです:
isFinite(): 値が NaN/正の無限大/負の無限大の場合は false を返し、それ以外の場合は true を返します。
parseFloat(): (文字列のプレフィックス部分) から浮動小数点数を取得します。失敗した場合は NaN が返されます。
3) ブール型
======================
(省略)
4). string 型
========================
JavaScript の String 型は元々特別なものではありませんでしたが、適応させるために
「ブラウザ実装のハイパーテキスト環境」なので、いくつかの奇妙なメソッドが含まれています。例:
link(): String オブジェクト内のテキストの両端に、HREF 属性を持つハイパーリンク タグ
を配置します。
big(): String オブジェクト内のテキストの両端に 1 対の
タグを配置します。
次のメソッドはこれに似ています:
anchor()
blink()
bold() fixed()
fontcolor() fontsize()
italics ()
small()
strike()
sub()
sup()
さらに、文字列の主な複雑さは、JavaScript の toString の遍在性に由来します ( )
メソッド。これは、ブラウザ環境用の JavaScript が提供する非常に重要なメソッドでもあります。たとえば、オブジェクトを
宣言し、それを出力するために document.writeln() を使用した場合、IE では何が表示されるでしょうか?
次の例は、この問題を示しています:
//-------------------------------- - ------------------------
//toString() の応用
//-------- -- --------------------------------------------------
var
s = 新しいオブジェクト();
s.v1 = 'こんにちは、';
s.v2 = 'テスト!';
document.writeln(s.toString());
s.toString = function() {
return s.v1 s.v2;
document.writeln( s);
この例では、オブジェクトが独自の toString() メソッド
を再宣言 (オーバーライド) しない場合、そのメソッドが (writeln などによって) 文字列型として使用されることがわかります。 、Java Script
環境のデフォルトの toString() が呼び出されます。次に、JavaScript がこのオブジェクト
を理解する方法を再定義できます。
多くの JavaScript フレームワークは、「テンプレート」メカニズムを実装するときにこの機能を利用します。たとえば、
は次のように FontElement オブジェクトを定義します:
//-------------------------------- - ------------------------
// toString() を使用してテンプレート メカニズムを実装する簡単な原理
// ------ -------------------------------------------- ------ -
function FontElement(innerHTML) {
this.face = '宋体';
this.color = 'red'
// 詳細...
var ctx = innerHTML;
this.toString = function() {
return '
'
ctx '
' }
}
var obj = new FontElement('This is a test.');
// 次のコード行の記述に注意してください
document.writeln(obj); 🎜>
5) 関数タイプ
=======================
JavaScript 関数には、オブジェクト指向部分(これについては後述)、独自の機能のいくつかも広く使用されています。
まず、JavaScript のすべての関数は、呼び出しプロセス中に引数オブジェクトを持つことができます。この
オブジェクトはスクリプト解釈環境によって作成されます。引数オブジェクトを自分で作成する他の方法はありません。
引数は配列と見なすことができます。配列には長さ属性があり、各パラメータには argument[n]
を通じてアクセスできます。ただし、最も重要なことは、callee 属性を通じて
を実行している関数オブジェクトへの参照を取得できることです。
次の質問は興味深いものになります。Function オブジェクトには caller 属性があり、現在の
関数を呼び出している親関数オブジェクトへの参照を指します。
- JavaScript で呼び出し先/呼び出し元を通じて
期間の呼び出しスタックをトラバースできることがわかりました。引数は実際には Function の属性であるため、実行呼び出しスタック上の各関数のパラメータを実際に
走査することができます。以下のコードは簡単な例です:
//--------------------------------- - --------------------
//コールスタックの走査
//-------------- ------ -------------------------------------------- ----
関数 foo1 (v1, v2) {
foo2(v1 * 100)
}
関数 foo2(v1) {
foo3(v1 * 200); ;
}
function foo3(v1) {
var foo = argument.callee;
while (foo && (foo != window)) {
document.writeln('呼び出しパラメータ:
', ' ---------------
');
var args = foo.arguments, argn = args.length; 🎜>for (var i=0; i
'); }
document.writeln('
');
// 前のレベル
// run test
foo1(1 , 2);
2. JavaScript オブジェクト指向のサポート
--------
前の例では、実際に「型宣言」とオブジェクト型の「インスタンス」を作成します。
JavaScript では、関数を通じてオブジェクトの型を宣言する必要があります:
//-------------------------- -- -----------------------------
//JavaScript でのオブジェクト型宣言の正式なコード
// (将来的にはドキュメントでは、「オブジェクト名」は通常 MyObject に置き換えられます)
//-------------------------------- - -------------------------
関数オブジェクト名(パラメータリスト) {
this.property = 初期値; >
this.method = function (メソッドパラメータリスト) {
//メソッド実装コード
}
}
次に、このようなコードを通じてこのオブジェクトを作成できます。タイプ:
//------------------------------------------ ------ -------
//インスタンス作成の正式コード
// (今後のドキュメントでは「インスタンス変数名」と表記します)通常は obj)
//-------------------------------------- に置き換えられます。 ------ -----------
var インスタンス変数名 = 新しいオブジェクト名 (パラメータ リスト);
次に、「」の具体的な実装と奇妙な点をいくつか見てみましょう。 JavaScript の特性の「オブジェクト」。
1) JavaScript のオブジェクト指向メカニズムにおける関数の 5 つの要素
------
「オブジェクト名」 (MyObject() など)。この関数は、以下の言語の役割:
(1) 通常の関数
(2) 型宣言
(3) 型実装
(4) クラス参照
(5) オブジェクトコンストラクター
一部のプログラマ (Delphi プログラマなど) は、型宣言を実装から切り離すことに慣れています。たとえば、delphi
では、インターフェイス セクションは型または変数を宣言するために使用され、実装セクションは型
の実装コード、または実行用の関数とコード プロセスを記述するために使用されます。
しかし、JavaScript では型宣言と実装が混在しています。オブジェクト
の型 (クラス) は関数を通じて宣言され、this.xxxx はオブジェクトが持つことができる属性またはメソッドを示します。
この関数は「クラス参照」でもあります。 JavaScript では、オブジェクト
の特定の型を識別する必要がある場合、「クラス参照」を保持する必要があります。 ——もちろん、これはこの機能の名前です
。 instanceof 演算子は、インスタンスのタイプを識別するために使用されます。その応用例を見てみましょう:
//----------------------- - ----------------------------------
// JavaScript でのオブジェクトの型識別
/ / 構文: オブジェクト インスタンス クラス参照
//------------------------------------- ---- ----------------
function MyObject() {
this.data = 'テストデータ'
}
; // ここで MyObject () はコンストラクターとして使用されます
var obj = new MyObject();
var arr = new Array();
// ここで MyObject はクラス参照として使用されます
document.writeln(MyObject のオブジェクトのインスタンス);
document.writeln(MyObject のインスタンス)
===============
(
= ===============
次の内容:
2. JavaScript オブジェクト指向のサポート
------ --
2). JavaScript でのリフレクション メカニズムの実装
3)。キーワード
を使用した操作。instanceof を使用した操作。キーワード
6). その他のオブジェクト指向キーワード
4. インスタンスとインスタンス参照
>6. 関数コンテキスト
7. オブジェクト型チェックの問題
2) JavaScript でのリフレクション メカニズムの実装
------
for..in 構文を使用した JavaScript。ただし、JavaScript は、「プロパティ」、「メソッド」、および「イベント」を明確に区別しません。したがって、JS
では、プロパティの型チェックが問題になります。次のコードは、for..in と属性識別の簡単な使用例です:
//-------------------------- --- -----------------------------
// JavaScript での for..in の使用と属性の識別
//-- -------------------------------------- ------ -----
var _r_event = _r_event = /^[Oo]n.*/;
var colorSetting = {
メソッド: 'red',
イベント: 'blue',
property: ''
}
var obj2 = {
a_method : function() {},
a_property: 1,
onclick: 未定義
}
function propertyKind(obj, p) {
return (_r_event.test(p) && (obj[p]==未定義 || typeof(obj[p])=='function ')) ? 'イベント '
: (typeof(obj[p])=='関数') 'メソッド'
: 'プロパティ'
}
var objectArr = ['window', ' obj2'];
for (var i=0; i
for ', objectArr[i] , '
' );
var obj = eval(objectArr[i]);
for (var p in obj) {
var kind = propertyKind(obj, p); 🎜>document.writeln( 'obj.', p, ' は ', kind.fontcolor(colorSetting[kind]), ': ', obj[p], '
');
}
開発者によって見落とされがちな事実は、JavaScript 自体にはイベント システムがないということです。通常
JavaScript で通常使用する onclick やその他のイベントは、実際には IE の DOM モデルによって提供されます。よりコアな
の観点から見ると、IE は COM のインターフェイス属性を通じて一連のイベント インターフェイスを DOM に公開します。
JS で「属性がイベントであるかどうか」を適切に識別できない理由は 2 つあります。
- COM インターフェイス自体にはメソッド、プロパティ、イベントのみがあり、これらはすべて一連のメソッドを介して渡されます。公開するメソッドを取得/設定します。
- JavaScript には、独立した「イベント」メカニズムがありません。
したがって、イベントの識別方法は、属性名が文字列 'on' で始まるかどうかを検出することであることがわかります ('On'
で始まるのは Qomo の規則です)。次に、DOM オブジェクト内のイベントはハンドラー関数を指定する必要がないため、この場合、イベント ハンドルは null になります (Qomo は同じ規則を採用します)。ユーザーは、obj2 と同様に、値を指定してイベントを定義できます。未定義。したがって、「イベント」の判定条件は
("属性はon/Onで始まる" && ("値はnull/未定義" || "型は関数です")という複雑な式に処理されます。 ))
また、上記コードの実行結果から判断すると。 DOM オブジェクトで for..in を使用すると、
オブジェクトのメソッドを列挙できません。
最後にもう 1 点。実際、多くの言語実装では、「イベント」は「オブジェクト指向」言語機能ではなく、特定のプログラミング モデルによって提供されます。たとえば、Delphi のイベント駆動メカニズムは、Win32
オペレーティング システムのウィンドウ メッセージ メカニズムによって提供されるか、コンポーネント/クラスの
イベント処理関数をアクティブに呼び出すユーザー コードによって実装されます。
「イベント」は「プログラミングモデルをどのように駆動するか」という仕組み・問題であり、言語そのものの問題ではありません。しかし、PME(プロパティ/メソッド/イベント)に基づくOOPの概念は人々の心に深く根付いており、プログラミング言語やシステムがその特性を示すと、「イベント」を誰が達成したかなど誰も気にしなくなります。
3) キーワード
------
での this との使用 JavaScript オブジェクト システムでは、this キーワードは 2 つの場所で使用されます。
- 構築中コンバータ関数は、新しく作成されたオブジェクト インスタンスを参照します
- オブジェクトのメソッドが呼び出されるとき、メソッドを呼び出したオブジェクト インスタンスを参照します
関数が (オブジェクトではなく) 通常の関数として使用される場合メソッド) が呼び出されると、関数内の this キーワード
はウィンドウ オブジェクトを指します。同様に、this キーワードがどの関数にも含まれていない場合は、
window オブジェクトも指します。
JavaScript では関数とメソッドの間に明確な区別がないためです。したがって、コードの一部は奇妙に見えます:
//------------------------------------- --- -------------------
// 関数
のいくつかの可能な呼び出し形式 //-------- ----- -------------------------------------- --
function foo( ) {
// 以下は、このメソッドを呼び出すオブジェクト インスタンスを参照します。
if (this===window) {
document.write('関数を呼び出します。 ', '
') ;
}
else {
document.write('オブジェクトごとにメソッドを呼び出します: ', this.name, '
');
}
function MyObject(name) {
// これは、新しいキーワードの新しく作成されたインスタンスを指します
this.name = name;
this.foo = foo; ;
}
var obj1 = new MyObject('obj1');
var obj2 = new MyObject('obj2'); テスト 1: foo() を関数として;
// テスト 2: オブジェクト メソッドとして呼び出します
obj2.foo(); 3: 関数を「指定されたオブジェクト」として呼び出します。「メソッド呼び出し
foo.call(obj1);
foo.apply(obj2);
上記のコードでは、obj1/obj2 による foo( ) は非常に一般的な呼び出しメソッドです。 ——つまり、
はコンストラクタ上で関数をオブジェクトとして指定するメソッドです。
テスト 3 の call() と apply() は非常に特殊です。
このテストでは、foo() は通常の関数として呼び出されますが、JavaScript 言語機能
を使用すると、()/apply() を呼び出すときに foo() を指定するためにオブジェクト インスタンスを渡すことができます。
のコンテキストに表示される this キーワードへの参照。 ——現時点では foo() はオブジェクト メソッド呼び出しではなく、通常の
関数呼び出しであることに注意してください。
は、「このメソッドを呼び出すオブジェクト インスタンスを示す」とやや似ており、with() 構文は、
を「コード内でデフォルトでオブジェクト インスタンスを使用する」ことを修飾するためにも使用されます。——with() 構文が使用されていない場合、
の場合、このコードは外側の with() ステートメントの影響を受けます。外側の with() がない場合、
の場合、「 デフォルトのオブジェクト インスタンス」使用するのは窓になります。
ただし、this と with キーワードは相互に影響を与えないことに注意してください。次のコードのような:
//-------------------------------------- - ------------------
// テスト: this と with キーワードは相互に影響しません
//---------- -----------------------------------------------
function test() {
with (obj2) {
this.value = 8;
}
}
var obj2 = new Object();
obj2.value = 10;
test();
document.writeln('obj2.value: ', obj2.value, '
');
document.writeln('window.value: ', window . value, '
');
呼び出しの完了後に、このようなコードが obj2.value 属性を 8 に設定することは期待できません。これらの
コード行の結果は次のようになります: window オブジェクトには追加の value 属性があり、その値は 8 です。構文
with(obj){...} は、obj の既存の属性の読み取りを制限することしかできませんが、積極的に
宣言することはできません。 with() のオブジェクトに指定された属性がない場合、または with() がオブジェクトではないデータを修飾すると、結果は例外になります。
4). in キーワードを使用した操作
------
オブジェクトのメンバー情報を反映するために for..in を使用することに加えて、JavaScript では in を直接使用することもできます。
オブジェクトに指定された名前の属性があるかどうかを検出するキーワード。
in キーワードが頻繁に言及される理由は、属性が存在するかどうかを検出する機能ではないためです。そのため、
の初期のコードでは、多くの人が "if (!obj.propName) { }" この方法は、propName
が有効なプロパティかどうかを検出します。 ——多くの場合、「属性が存在するかどうか」をチェックするよりも、妥当性をチェックする方が
実用的です。したがって、この場合、 in はオプションの公式ソリューションにすぎません。
in キーワードの重要な用途は、高速文字列検索です。特に「文字列
が存在するかどうか」だけを判断する必要がある場合。たとえば、100,000 個の文字列が配列に格納されている場合、検索効率は
非常に悪くなります。
//------------------------------------------ ------------
// オブジェクトを使用して
を取得します//--------------------- --- -----------------------------
function arrayToObject(arr) {
for (var obj= new Object) ()、i=0、imax=arr.length; i
var
arr = ['abc', 'def', 'ghi']; // ますます...
obj = arrayToObject(arr);
function valueInArray( v) {
for (var i=0, imax=arr.length; i
return false;
function valueInObject(v) {
return v in obj;
}
このキーワードを使用する方法もあります。いくつかの制限があります。たとえば、検索できるのは文字列だけですが、配列要素には任意の値を指定できます。さらに、arrayToObject() にはオーバーヘッドもあるため、ルックアップ セットを頻繁に変更するのには適していません。
最後に、(お気づきかと思いますが) オブジェクト
を使用して検索すると、検索データは正確に特定されませんが、配列は結果の添字を指すことができます。
8. JavaScript オブジェクト指向のサポート
~~~~~~~~~~~~~
(続き)
2.オブジェクト指向オブジェクトのサポート
------
(続き)
5) JavaScript の instanceof キーワード
------
を使用した操作インスタンスのタイプを検出するために、instanceof キーワードが提供されます。これについては、以前にその「五重のアイデンティティ」について議論する際にすでに議論されました
。しかし、instanceof の問題は、次のような
プロトタイプ チェーン全体を常に列挙して型を検出することです (プロトタイプの継承の原理については「構築と破壊」セクションで説明します)。
//---- --- --------------------------------------------------- ---
//instanceof
の使用時の問題//--------------------------------- - -----------------------
function MyObject() {
// ...
}
function MyObject2 () {
// ...
}
MyObject2.prototype = new MyObject();
obj1 = new MyObject(); );
document.writeln(obj1 instanceof MyObject, '
');
document.writeln(obj2 instanceof MyObject, '
'); obj1 と obj2 はどちらも MyObject のインスタンスですが、異なるコンストラクター
によって生成されます。 ——これはオブジェクト指向の理論では正しいことに注意してください。obj2 は MyObject のサブクラス インスタンスであるため、obj1 と同じ特性を持っています。アプリケーションでは、これは obj2 の多態性の現れの 1 つです。
しかし、それでも、次の問題に直面しなければなりません: obj2 と obj1 が同じタイプの
インスタンスであるかどうかをどうやって知るか? ——つまり、コンストラクターまで同じということですか?
instanceof キーワードはそのようなメカニズムを提供しません。この検出を実装する機能を提供するのは、
Object.constructor プロパティです。 --しかし、まず覚えておいてください、これは思っているよりも使いにくいということです。
それでは、まず質問を終わりにしましょう。コンストラクター属性にはすでに「構築と破壊」の問題が含まれています。
これについては後で説明します。 「プロトタイプの継承」と「構築と破壊」は、JavaScript の OOP
における主要な問題、中核問題、そして「致命的な問題」です。
6) null と未定義
------
JavaScript では、null と未定義が私を混乱させました。次のテキストは、
をより明確に理解する (またはより混乱させる) のに役立ちます。
- null はキーワードであり、unknown は Global オブジェクトのプロパティです。
- null はオブジェクト (プロパティやメソッドを持たない空のオブジェクト) で、未定義のクラス
型の値です。次のコードを試してください:
document.writeln(typeof null);
document.writeln(typeof unknown)
- オブジェクト モデルでは、すべてのオブジェクトは Object またはそのサブクラスですが、null の場合は例外です。オブジェクト:
document.writeln(null instanceof Object);
- null は未定義と「等しい (==)」ですが、未定義と「一致 (===)」ではありません:
document.writeln( null == 未定義);
document.writeln(null == 未定義);
- null と unknown は両方とも操作中に false に変換できますが、false と等価ではありません:
document.writeln( !null, !unknown);
document.writeln(null==false);
8. JavaScript オブジェクト指向のサポート
~~~~~~~~~~~~~~~~~
(続き)
3. 構築、破壊、試作品の問題
----- ---
オブジェクトはコンストラクター関数を通じて生成する必要があることはすでにわかっています。最初にいくつかの点を覚えておきましょう:
- コンストラクターは通常の関数です
- プロトタイプはオブジェクト インスタンスです
- コンストラクターにはプロトタイプのプロパティがありますが、オブジェクト インスタンスにはありません
- (継承の場合)オブジェクト インスタンスのコンストラクター属性は、コンストラクター
を指します。 - 3 番目と 4 番目の項目から派生します。 obj.constructor.prototype は、オブジェクト
のプロトタイプを指します。例を分析して、
を使用した JavaScript の「継承されたプロトタイプ」宣言と構築プロセスを説明します。
//------------------------------------------ ------------
//プロトタイプ、構築、継承を理解する例
//-------- - -------------------------------------
function MyObject() {
this . v1 = 'abc';
関数 MyObject2() {
this.v2 = 'def';
MyObject2.prototype = new MyObject(); 🎜 >
var obj1 = new MyObject();
var obj2 = new MyObject2();
1) new() キーワードの正式なコード
------
まず、コード行「obj1 = new MyObject()」の新しいキーワードを見てみましょう。
new キーワードは、新しいインスタンスを生成するために使用されます (私は予約語をキーワード
と呼ぶことに慣れていることをここに付け加えておきます。さらに、JavaScript の new キーワードも演算子です) 、このインスタンスのデフォルト属性
は、(少なくとも) コンストラクター関数のプロトタイプ属性 (prototype) への参照を保持します (ECMA Javascript
仕様では、オブジェクトのこの属性名は __proto__ として定義されています)。 。
すべての関数は、コンストラクターとして使用されるかどうかに関係なく、一意のプロトタイプ オブジェクトを持ちます。
JavaScript の「組み込みオブジェクト コンストラクター」の場合、内部プロトタイプを指します。デフォルトでは、JavaScript
は「空の初期オブジェクト インスタンス (null ではない)」を構築し、それをプロトタイプ参照で指します。ただし、関数のこのプロトタイプに新しいオブジェクトを割り当てると、新しいオブジェクト インスタンスはそのプロトタイプへの参照を保持します。
次に、構築プロセスは MyObject() を呼び出して初期化を完了します。 ——これは単なる「初期化」であることに注意してください。
このプロセスを明確に説明するために、コードを使用してこのプロセスを正式に説明します。
//--------------------- - -----------------------------------
//new() キーワードの正式コード
//------------------------------------------ --- ---------
function new(aFunction) {
// 基本オブジェクト インスタンス
var _this = {};
// プロトタイプ参照
var _proto = aFunction.prototype;
/* 互換性のある ECMA スクリプトの場合
_this.__proto__ = _proto;
*/
// プロトタイプ (内部) ゲッターの属性にアクセスするために追加します
_this._js_GetAttributes= function(name) {
if (_existAttribute.call(this, name))
return this[name]
else if (_js_LookupProperty.call(_proto , name))
retrun OBJ_GET_ATTRIBUTES.call(_proto, name)
else
return unknown;
}
// プロトタイプ セッターの属性にアクセスするための (内部) を追加
_this._js_GetAttributes = function(name, value) {
if (_existAttribute.call(this, name))
this[name] = value
else if (OBJ_GET_ATTRIBUTES.call(_proto, name) !== value) {
this[name] = value // 現在のインスタンスの新しいメンバーを作成します
}
}
// コンストラクターを呼び出して初期化を完了します (存在する場合) を渡しますargs
aFunction.call(_this);
// Return object
return _this;
したがって、次の 2 つの点がわかります。コンストラクター (aFunction) 自体は、渡されたこのインスタンスを「初期化」するだけであり、
はオブジェクト インスタンスを構築しません。
- 構築プロセスは実際には new() キーワード/演算子の内部で発生します。
さらに、コンストラクター(aFunction)自体はプロトタイプを操作する必要はなく、また、これを返す必要もありません。
2). ユーザー コードによって維持されるプロトタイプ チェーン
------
次に、プロトタイプ チェーンと構築プロセスについて詳しく説明します。これは次のとおりです:
- プロトタイプ チェーンはユーザー コードによって作成され、new() キーワードはプロトタイプ チェーンの維持には役立ちません
Delphi コードを例として、継承関係を宣言するときに、次のようにします。次のコードを使用できます:
//----------------------------------------------------- -------- ----------------
// delphi で使用される「クラス」型宣言
//-------- --------- --------------------------------------
type
TAnimal = class (TObject); // 動物
TMammal = class(TAnimal); // 哺乳類
TCanine = class(TMammal); // イヌ科哺乳類
TDog; TCanine); // Dog
現時点では、Delphi のコンパイラはコンパイル テクノロジを通じて継承関係リストを維持します。このリンクされたリストは、次のような
コードを通じてクエリできます:
//---------------------------- --- ----------------------------
//delphi で継承関係リンクリストを使用するためのキーコード
/ /--- ---------------------------------------------- ---- ----
関数 isAnimal(obj: TObject): boolean;
begin
結果 := obj は
var
Dog := TDog ;
// ...
dog := TDog.Create();
writeln(isAnimal(dog)); Delphi ユーザー コードでは、継承関係のリンク リストを直接継承する必要はありません。これは、
Delphi が厳密に型指定された言語であるため、class() キーワードで宣言された型を処理するときに、Delphi のコンパイラー
がユーザーのためにこの継承チェーンをすでに構築しているためです。 ——このプロセスはステートメントであり、
コードの実行ではないことに注意してください。
JavaScript では、オブジェクトが特定の基本クラスのサブクラス オブジェクトであるかどうかを知る必要がある場合、
手動でリンク リストを管理する必要があります (Delphi の例と同様)。もちろん、この連結リストは型継承ツリーとは呼ばれず、「(オブジェクトの)プロトタイプ連結リスト」と呼ばれます。 ——JSには「クラス」型がありません。
前の JS および Delphi コードを参照してください。同様の例は次のとおりです:
//----------------------- ----------------------------------
//JSの「プロトタイプリンクリスト」のキーコード
//------------------------------------------ ----- ----------
// 1. コンストラクター
function Animal() {};
function Mammal() {}; {};
function Dog() {};
// 2. プロトタイプのリンクされたリスト
Mammal.prototype = new Animal();
Dog.prototype = new Canine();
// 3. 関数の例
function isAnimal(obj) {
return obj instanceof Animal; >var
Dog = new Dog();
document.writeln(isAnimal(dog));
ご覧のとおり、JS ユーザーコードでは、「プロトタイプリンク」の構築メソッドがlist" は次のコード行です:
"現在のクラスのコンストラクター関数".prototype = "直接の親クラスのインスタンス"
これは Delphi のような言語とは異なります: 保守の本質プロトタイプ チェーンは宣言ではなくコードを実行します。
では、「宣言ではなく実行」とはどういう意味でしょうか?
JavaScript にはコンパイル処理が必要です。この処理では主に「文法エラーの検出」、「文法宣言」、「条件付きコンパイル命令」を扱います。ここでの「文法宣言」は主に関数宣言を扱います。 ——これは、私が「関数は第一のタイプに属するが、オブジェクトはそうではない」と言っている理由の 1 つでもあります。
以下の例:
//-------------------------------------- --------- ---------------------
//関数宣言と実行文の関係(Firefox互換)
//-------- -------------------------------------- ----------
// 1. 出力 1234
testFoo(1234);
// 2. obj1
// を出力してみます。出力 obj2
testFoo(obj1);
try {
testFoo(obj2);
}
catch(e) {
document.writeln('Exception: ', e.description , '
');
}
// testFoo() を宣言します
function testFoo(v) {
document.writeln(v, '
'); 🎜>}
// オブジェクトを宣言します
var obj1 = {};
obj2 = {
toString: function() {return 'こんにちは、object.'}
}
// 4. 出力 obj1
// 5. 出力 obj2
testFoo(obj1);
testFoo(obj2); このサンプルコードを実行した結果JS 環境は次のとおりです:
------ -----------------------------
1234
未定義
例外: 'obj2' 未定義
[object オブジェクト]
こんにちは、obj
---------------------- ------------------------
問題は、オブジェクト変数が宣言される前に testFoo() が実行されることです。
形式の「直接宣言」は宣言前に参照することはできません。 ——この例では、2 番目と 3 番目の
入力が間違っています。
関数は宣言前に参照できますが、他の種類の値は宣言後に使用する必要があります。
これは、JavaScript では「宣言」と「実行時参照」が 2 つの処理であることを示しています。
さらに、「var」を使用して宣言する場合、コンパイラは最初に変数
が存在することを確認しますが、変数の値は「未定義」になることもわかります。 ——つまり、「testFoo(obj1)」は
例外をスローしません。ただし、obj1 に関する代入ステートメントが実行されるまで、通常の出力は行われません。
2行目と3行目、4行目と5行目の出力の違いを比較してください。
JavaScript は「宣言」ではなく「実行」を通じてプロトタイプ チェーンを維持するため、これは「プロトタイプ
チェーンはコンパイラではなくユーザー コードによって維持される」ことを意味します。
Basedこの推論に基づいて、次の例を見てみましょう:
//-------------------------------- -- ------------------------
// 例: 間違ったプロトタイプ チェーン
//--------- -- -------------------------------------------
// 1.コンストラクター
関数 Animal() {}; // 動物
関数 Mammal() {}; // 哺乳類
関数 Canine() {}; // イヌ科哺乳類2. プロトタイプチェーンを構築します
var インスタンス = new Mammal();
Mammal.prototype = new Animal();
// 3. テスト出力
var obj = new Canine();
document.writeln(obj instanceof Animal);
この出力により、間違ったプロトタイプ チェーンが確認できます。その結果、「イヌ科の哺乳類は動物ではない」ということになります。 。
根本的な原因は、「2. プロトタイプ チェーンの構築」の次のコード行が、var や
function のようにコンパイル時に「宣言」されて理解されるのではなく、解釈されて実行されることです。この問題を解決する方法は、コードの 3 行の
を変更して、その「実行プロセス」を論理的にすることです。
//-------- -- ------------------------------------
//上記例の修正コード(パート)
//------------------------------------------ -- -----------
// 2. プロトタイプ チェーンを構築します
Mammal.prototype = new Animal()
var instance = new Mammal(); Canine.prototype = インスタンス;
3) 構築プロセスでのプロトタイプ インスタンスの使用方法
------
引き続き Delphi を例に挙げます。構築プロセス中、Delphi はまず指定されたインスタンス サイズの
「空のオブジェクト」を作成し、次にプロパティに値を 1 つずつ割り当て、構築プロセスでメソッドを呼び出し、イベントをトリガーします。
JavaScript の new() キーワードに暗黙的に含まれる構築プロセスは、Delphi の構築プロセスと完全には一致しません。ただし、
コンストラクター関数で発生する動作は上記と似ています。
//-------------------------- - ----------------------------
//JSでの構築処理(形式コード)
//- --- ---------------------------------------------- --- ---
function MyObject2() {
this.prop = 3;
this.method = a_method_function;
if (you_want) {
this.method( ); 🎜>this.fire_OnCreate();
}
}
MyObject2.prototype = new MyObject(); // MyObject() の宣言は省略されます
var obj = new MyObject2 ( );
単一のクラスが参照オブジェクトとして使用される場合、JavaScript はこの構築プロセス中に Delphi
と同じ豊富な動作を行うことができます。ただし、Delphi の構築プロセスは「動的」であるため、実際には
Delphi は親クラス (MyObject) の構築プロセスも呼び出し、親クラスの OnCreate() イベントをトリガーします。
JavaScript にはそのような機能はありません。親クラスの構築プロセスは、プロトタイプ (プロトタイプ
属性) に値を割り当てるコード行でのみ発生します。その後、新しい MyObject2() がいくつ発生しても、
MyObject() コンストラクターは使用されません。 ——これは次のことも意味します:
- 構築プロセス中に、プロトタイプ オブジェクトは 1 回生成されます。新しいオブジェクトは、このプロトタイプ インスタンス
への参照のみを保持します (また、アクセスするには「コピー オン ライト」メカニズムを使用します)。そのプロパティ) を呼び出し、プロトタイプのコンストラクターを呼び出さなくなりました。
親クラスのコンストラクターが呼び出されなくなったため、Delphi の一部の機能は JavaScript で実装できません。
これは主に建設段階の一部のイベントと動作に影響します。 ——「オブジェクト構築プロセス中」の一部の
コードは、親クラスのコンストラクターに書き込むことができません。なぜなら、サブクラスを何度構築しても、今回のオブジェクトの構築処理では親クラスのコンストラクター内のコードは一切活性化されないからです。
オブジェクトの親クラス属性へのアクセスはプロトタイプのリンク リストに依存するため、JavaScript での属性へのアクセスは動的ですが、
の構築プロセスは静的であり、親クラスのコンストラクターにはアクセスしません。 ; Delphi 一部のコンパイル言語では、属性 (リーダーとライターを使用しないもの) へのアクセスは静的ですが、オブジェクトの構築プロセスは親クラスのコンストラクターを動的に呼び出します。
それでは、もう一度、 new() キーワードの正式なコードの次の行を明確に読んでください:
//--------------------- - ---------------------------------
// new() キーワードの正式コード
// -------------------------------------- ----- ------
function new(aFunction) {
// プロトタイプ参照
var _proto= aFunction.prototype
// ...
}
このプロセスで、JavaScript が行うことは「prototype_Ref の取得」ですが、Delphi などの他の言語
が行うことは「Inherited Create()」です。
8. JavaScript オブジェクト指向のサポート
~~~~~~~~~~~~~~~~~~
(続き)
4)。必須 ユーザーによって維持される別の属性: コンストラクター
------
前の内容を思い出してください:
- (継承モデルが正常に実装されている場合) オブジェクト インスタンスのコンストラクター属性コンストラクター オブジェクトを指します
- obj.constructor.prototype はオブジェクトのプロトタイプを指します
- Object.constructor プロパティを通じて、obj2 と obj1 が同じ型のインスタンスであるかどうかを検出できます
そして、プロトタイプチェーンはユーザーコードによって決定される必要があります。 プロトタイプ属性を維持するのと同じように、インスタンスのコンストラクター属性コンストラクター
もユーザーコードによって維持する必要があります。
JavaScript の組み込みオブジェクトの場合、constructor 属性は組み込みコンストラクター関数を指します。例:
//------------------------------------------ ------ ----------------
// 組み込みオブジェクトインスタンスのコンストラクタ属性
//---------- ---------- --------------------------------------------
var _object_types = {
'function' : 関数、
'boolean' : ブール値、
'regexp' : RegExp、
// 'math' : Math、
// 'デバッグ' : デバッグ、
// 'image ' : 画像;
// 'undef' : 未定義、
// 'dom' : 未定義、
// 'activex' : 未定義、
'vbarray' : VBArray、
' array' : 配列、
'string' : 文字列、
'date' : 日付、
'error' : エラー、
'enumerator' : 列挙子,
'number' : 数値、
'object' : オブジェクト
}
function objectTypes(obj) {
if (typeof obj !== 'object') return typeof obj;
if (obj == = null) return 'null';
for (var i in _object_types) {
if (obj.constructor===_object_types[i]) return i ;
}
return ' unknown';
}
// テストデータと関連コード
function MyObject() {
}
function MyObject2() {
}
MyObject2.prototype = new MyObject();
window.execScript(''
'Function CreateVBArray()'
' Dim a(2, 2)'
' CreateVBArray = a'
'関数の終了', 'VBScript');
document.writeln('