ホームページ > 記事 > ウェブフロントエンド > JavaScript を理解する
はじめに
プログラミングの世界には基本要素が 2 つだけあり、1 つはデータ、もう 1 つはコードです。プログラミングの世界は、データとコードが分かちがたく絡み合い、無限の生命力を発揮します。
データは本質的に静かで、常にその本質を維持しようとしますが、コードは本質的に活発で、常に世界を変えようとします。
ご存知のとおり、データ コード間の関係は、物質とエネルギーの関係に驚くほど似ています。データにも慣性があり、外力を加えるコードがなければ常に元の状態を維持します。コードはエネルギーのようなもので、その存在の唯一の目的は、データの元の状態を変更するために一生懸命働くことです。コードがデータを変更すると、データの抵抗により、コードの元の傾向にも影響が生じたり、変化したりします。場合によっては、データをコードに変換したり、コードをデータに変換したりすることもできます。E=MC2 のようなデジタル変換式も存在します。しかし、このデータとコードの間の矛盾しながらも統一された操作には、コンピューターの世界の法則が常に反映され、これらの法則はまさに私たちが作成するプログラム ロジックです。
ただし、プログラマーによって世界観が異なるため、これらのデータとコードは異なって見えます。その結果、異なる世界観を持つプログラマーが独自の方法論を用いてプログラミングの世界の進化と発展を推進しています。
ご存知のとおり、今日最も人気のあるプログラミングのアイデアは、オブジェクト指向プログラミングのアイデアです。なぜオブジェクト指向の考え方がプログラミングの世界で急速に普及するのでしょうか?なぜなら、オブジェクト指向の考え方では、データとコードが初めて 1 つに結合され、それが単純なオブジェクト概念でプログラマーに提示されるからです。これにより、元の乱雑なアルゴリズムとサブルーチン、および絡み合った複雑なデータ構造が突然、明確で整然としたオブジェクト構造に分割され、それによって私たちの心の中のデータとコードの乱雑な結び目が明確になります。私たちはより明晰な心を持ち、別のレベルの思考からより広大なプログラミングの世界を探索することができます。
第5世祖ホンレンは『対象真経』の説教を終えた翌日、弟子たち全員にこう言いました。最年長の弟子である沈秀は、最も理解力のある兄弟として認められており、彼の詩には次のように書かれています。埃っぽい!」。この聖句が出てくるとすぐに、兄弟たちの間ですぐにセンセーションを巻き起こし、とてもよく書かれていると皆が言いました。火の頭の僧侶である恵能だけが、それを見た後、静かにため息をつき、壁にこう書きました。 」それから彼は首を振って立ち去りました。慧能のガタを読んだ人は皆、「めちゃくちゃに書かれていて理解できない」と言います。紅蓮先生は沈秀の詩を読んで賞賛にうなずき、その後恵能の詩を見て静かに首を横に振った。その夜、紅蓮は静かに慧能を瞑想室に呼び、長年大切にしていたソフトウェア経典を教え、月明かりの下で一晩逃がしました...
その後、慧能は師の高い期待に本当に応えました。 . 南に禅宗のもう一つの広大な空を創造しました。フイネンが持ち去ったソフトウェア教典の一つが「JavaScript教典」だった!
シンプルさに戻る
JavaScript を理解するには、まずオブジェクトとクラスの概念を手放し、データとコードの原点に戻る必要があります。前述したように、プログラミングの世界にはデータとコードという 2 つの基本要素しかなく、これら 2 つの要素は絡み合っています。 JavaScript は、データとコードを最も原始的なレベルまで単純化します。
JavaScript のデータは非常に簡潔です。単純なデータには、未定義、null、ブール、数値、文字列の 5 つのタイプしかありませんが、複雑なデータにはオブジェクトという 1 つのタイプしかありません。これは、世界の最も基本的な要素を金属、木、水、火、土に分類し、他の複雑な物質はこれら 5 つの基本要素から構成されるという古典的な中国の単純唯物論に似ています。
JavaScript のコードは、関数という 1 つのフォームにのみ反映されます。
注: 上記の単語はすべて小文字です。数値、文字列、オブジェクト、関数などの JavaScript 組み込み関数と混同しないでください。ご存知のとおり、JavaScript 言語では大文字と小文字が区別されます
JavaScript の識別子、定数、変数、パラメーターは、unfined、null、bool、number、string、object、および function 型の 1 つであり、typeof が返す型です。値。これ以外のタイプはありません。
まず単純なデータ型について話しましょう。
未定義: すべての未知のもの、何もないもの、想像できないものを表し、コードはそれを処理できません。 petrelrelure、吹き飛ばされた、涙、涙、彼女は彼女が彼女に彼女が彼女をすべてレースすることを望んでいる彼女が彼女が彼女に必要とする彼女が彼女に彼女をすべてレースすることを望んでいる彼女は彼女が彼女に必要とする彼女が彼女に必要とする彼女が彼女に必要とする彼女が彼女に必要とする彼女が必要とすることを望んでいますE 任意の変数または属性に「未定義」を割り当てることができますが、これは変数がクリアされることを意味するのではなく、追加の属性を持つことになります。
null: コンセプトはありますが、何もありません。何もないところに何かがあるように見え、何かの中に何もないように見える。想像するのは難しいですが、すでにコードで処理できます。注: Typeof (Null) は Object を返しますが、NULL は Object ではなく、NULL 値を持つ変数は Object ではありません。
ブール値: はい、いいえ、いいえ、疑いはありません。正しいことは正しい、間違っていることは間違っている、絶対に明らかです。コードによって処理でき、コードのフローを制御することもできます。
NaN が数値計算に関与する構造は NaN であり、NaN != NaN です。
文字列: 機械の信号ではなく、人間にとって合理的なもの。人間とコンピューターの情報通信、人間の意図のコード理解などはすべてそれに依存しています。
単純型はオブジェクトではなく、JavaScript にはこれらの単純型をオブジェクト化する機能がありません。単純型の定数値が直接割り当てられている識別子、変数、パラメータはオブジェクトではありません。
いわゆる「オブジェクト化」とは、データとコードを複雑な構造に編成する機能です。 JavaScript では、オブジェクト型と関数型のみがオブジェクト化機能を提供します。
クラスはありません
Objectはオブジェクトの型です。 JavaScript では、データやコードがどれほど複雑であっても、それらをオブジェクトの形式でオブジェクトに整理できます。
しかし、JavaScript には「クラス」という概念がありません。
多くのオブジェクト指向プログラマにとって、これはおそらく JavaScript を理解するのが最も難しいことです。はい、ほとんどすべてのオブジェクト指向の本で最初に話されるのは、オブジェクト指向の柱である「クラス」の概念です。突然「カテゴリー」がなくなり、私たちは精神的な支えを失ったように感じ、自分に主人がいないように感じます。オブジェクトやクラスを手放して、「オブジェクトにルートがなく、型が見えない」状態に到達するのは簡単ではないようです。
それでは、まず JavaScript プログラムを見てみましょう:
var life = {};
for(life.age = 1; life.age {
“switch(life.age)
”
ケース 1: life.body ";
life .gill = "エラ";
life.body = "オタマジャクシ";
life.say = function(){alert(this.age+this.body+"-"+this) .tail+","+this.gill)} ;
ブレーク; life.lung = "肺" Say = function(){alert(this.age+this.body+"-"+this.legs+","+this .lung)};
生命が誕生したとき、それはプロパティやメソッドを持たない単なるオブジェクトでした。最初のライフプロセスには、「卵細胞」のように見える body 属性と Say メソッドがあります。第二の人生で「尻尾」と「エラ」が生えた、それは明らかに「オタマジャクシ」だった。 3度目の人生で尾と鰓の属性は消失したが、「4本の足」と「肺」が生え、脚と肺の属性を獲得し、最終的には「カエル」となった。豊かな想像力があれば、ハンサムな「王子様」に変身させたり、美しい「お姫さま」などと結婚させたりすることもできるかもしれません。ただし、このプログラムを読んだ後、次の質問について考えてください:
クラスは必ず必要ですか?
子供の頃の「お母さんを探している小さなオタマジャクシ」のおとぎ話をまだ覚えていますか?おそらく昨夜、あなたのお子さんはたまたまこの美しいおとぎ話を聞きながら眠りに落ちたのでしょう。かわいい小さなオタマジャクシは、自分の種類が進化し続けるうちに、徐々に母親と同じ「種類」になり、母親を見つけました。このおとぎ話に含まれるプログラミング哲学は次のとおりです。オブジェクトの「クラス」はゼロから生まれ、進化し続け、最終的には消滅します...
「クラス」は確かに複雑な現実を理解するのに役立ちます 世界、この混沌とした現実世界分類する必要があります。しかし、思考が「カテゴリー」に縛られてしまうと、「カテゴリー」が「飽き」てしまいます。想像してみてください。生物が最初から固定の「クラス」を割り当てられたとしても、進化することはできるでしょうか?オタマジャクシはカエルになれるでしょうか?おたまじゃくしが母親を探している話も子供たちに話してもらえますか?
したがって、JavaScript には「クラス」は存在せず、クラスは非表示になり、オブジェクトと統合されています。 「クラス」という概念を手放したからこそ、JavaScriptのオブジェクトは他のプログラミング言語にはない生命力を持っています。
この時点で、心の奥底で何かを感じ始めたら、あなたは JavaScript の禅を徐々に理解し始めています。
関数の魔法
次に、JavaScript 関数の魔法について説明します。
JavaScript コードには関数の形式が 1 つだけあり、関数は関数の型です。おそらく他のプログラミング言語にはプロシージャやメソッドなどのコード概念がありますが、JavaScript では関数の形式は 1 つだけです。関数を記述するときは、関数型のエンティティを作成するだけです。次のプログラムを見てください:
function myfunc()
{
alert("hello");
};
alert(typeof(myfunc));
このコードを実行すると、typeof(myfunc) が表示されます。関数を返します。上記の関数を作成する方法「定義式」と呼びます。次の「変数式」に書き換えます。したがって、typeof(myfunc) も関数を返します。 実際、これら 2 つの関数の記述方法は同等であり、いくつかの小さな違いを除いて、それらの内部実装はまったく同じです。つまり、作成する JavaScript 関数は単なる名前付き変数であり、変数の型は関数であり、変数の値は作成した関数のコード本体です。
あなたは賢明で、すぐにさらに質問するかもしれません: 関数は単なる変数であるため、変数には任意に値を割り当ててどこでも使用できます???/p>
次のコードを見てみましょう:
var myfunc = function ( )
}; func(); //myfunc への 2 回目の呼び出しでは、yes が出力されます
このプログラムを実行した結果、答えは「はい」です。関数が初めて呼び出された後、関数変数には新しい関数コード本体が割り当てられるため、関数が 2 回目に呼び出されるときは、異なる出力が表示されます。
さて、上記のコードを最初に定義された関数形式に変更しましょう:
function myfunc ()
{
alert("hello");
};
myfunc() // ここで myfunc を呼び出し、hello の代わりに Yea を出力します。
function myfunc ()
{
alert("yeah");
};
myfunc(); //myfunc はここで呼び出され、当然、yeah を出力します
たとえば、この JavaScript コードを 2 つの部分に分割する場合は、HTML に記述し、 タグを使用して次のように 2 つの部分に分割します。
<script><br> function myfunc () <br> {<br>alert ("hello");<br> };<br> myfunc(); //ここで myfunc を呼び出して hello<br></script>
<script><br> function myfunc ()</p> {<p>alert("yeah ");</p> }; <p> myfunc(); //ここで Myfunc が呼び出され、yeah が出力されます</p></script>
この時点で、出力は順番に表示されます。これは、JavaScript が実際に部分的に実行されていることも証明しています。
コード内で定義された関数ステートメントが最初に実行されるという点は、静的言語のコンパイルの概念に少し似ています。したがって、この機能を JavaScript の「プリコンパイル」と呼ぶ人もいます。
ほとんどの場合、これらの詳細にこだわる必要はありません。 1 つだけ覚えておいてください。JavaScript のコードも一種のデータであり、任意に割り当てたり変更したりすることもでき、その値はコードのロジックです。ただし、一般的なデータとは異なり、関数を呼び出して実行することができます。
しかし、JavaScript 関数がこの機能のみに優れているのであれば、C++ の関数ポインター、DELPHI のメソッド ポインター、C# のデリゲートと比較すると、これはどれほど奇妙なことでしょう。ただし、JavaScript 関数の魅力は他の 2 つの側面にも反映されています。1 つは、関数型自体もオブジェクト化できる機能であり、2 つ目は、関数とオブジェクトを超越的に組み合わせる機能です。
素晴らしいオブジェクト
まず、関数のオブジェクト化機能について話しましょう。
どの関数でも属性を動的に追加または削除できます。これらの属性は、単純な型、オブジェクト、またはその他の関数です。つまり、関数はオブジェクトの特性をすべて備えており、関数をオブジェクトとして使用できます。実際、関数はオブジェクトですが、通常のオブジェクトよりも括弧「()」演算子が 1 つ多くあり、この演算子は関数のロジックを実行するために使用されます。つまり、関数自体は引き続き呼び出すことができますが、まったく同じであることを除いて、一般オブジェクトを呼び出すことはできません。以下のコードを見てください:
function Sing()
{
with(arguments.callee)
alert(author + ":" + poem);
};
Sing.author = "李白";
Sing.poem = " 漢の秦の時代の月は、玉関路に行くとすぐに側室を照らします。";
Sing();
Sing.author = "李 Zhan";
Sing.poem = "太陽が昇る漢の時代の空に、月は陰の山の前に沈みます。私の娘の笛は三千年も歌い続けています。」;
Sing();
このコードでは、Sing 関数を定義した後、著者と詩の属性が Sing 関数に動的に追加されます。著者と詩の属性を別の著者と詩に設定すると、Sing() を呼び出したときに異なる結果が表示されます。この例では、JavaScript の関数がオブジェクトの本質であることを詩的な表現で理解するとともに、JavaScript 言語の美しさを感じてもらうことができます。
さて、上記の説明から、関数型のものはオブジェクト型と同じであることが理解できるはずです。これらの「オブジェクト」には「プロパティ」と「メソッド」の両方があるため、実際にこのように見ることができます。しかし、次のコードは新たな疑問をもたらします:
var anObject = {}; //オブジェクト
anObject.aProperty = "オブジェクトのプロパティ" //オブジェクトのプロパティ
anObject.aMethod = function(){alert( "オブジェクトのメソッド")}; //オブジェクトのメソッド
//主に以下を見てください:
alter(anObject["aProperty"]) //オブジェクトを配列として使用し、プロパティ名を使用できます。プロパティにアクセスするための添字として
anObject["aMethod"](); //オブジェクトを配列として使用し、メソッド名を添字として使用してメソッドを呼び出すことができます
for( var s in anObject) //すべてを走査します反復処理用のオブジェクトのプロパティとメソッド
alert( s + " is a " + typeof(anObject[s]));
関数型のオブジェクトにも同じことが当てはまります:
var aFunction = function() {}; //関数
aFunction.aProperty = "関数のプロパティ "; //関数のプロパティ
aFunction.aMethod = function(){alert("関数のメソッド")} //関数のメソッド
/ /主に以下を見てください:
alert(aFunction["aProperty"]) //関数を配列として使用し、属性名を添字として使用してプロパティにアクセスできます
aFunction["aMethod"](); ) // 関数を走査するすべての属性とメソッドが反復されます
Alert (S + "is a" + Typeof (AFUNCTION [s]);
はい、プロパティ名またはメソッド名を添字として使用すると、オブジェクトと関数にアクセスして配列のように処理できます。では、それは配列と考えるべきでしょうか、それともオブジェクトと考えるべきでしょうか?
配列は線形データ構造としてみなされるべきであることはわかっています。線形データ構造は一般に特定のルールを持ち、統一されたバッチ反復操作に適しています。オブジェクトは個別のデータ構造であり、分散した個人化されたものを記述するのに適しており、粒子に似ています。したがって、「オブジェクトは JavaScript の波ですか、それとも粒子ですか?」と尋ねることもできます。
物体量子論があるなら、答えは波動粒子双対性であるに違いありません。
したがって、JavaScript の関数とオブジェクトは、オブジェクトと配列の両方の特性を持ちます。ここでの配列は「辞書」と呼ばれ、任意に拡張できる名前と値のペアのコレクションです。実際、オブジェクトと関数の内部実装は辞書構造になっていますが、この辞書構造は厳密かつ絶妙な構文によって豊かな外観を示します。量子力学が、ある場所では粒子を使用して問題を説明し、対処するのと同じように、別の場所では波を使用します。必要に応じて、オブジェクトまたは配列の使用を自由に選択して、問題を説明したり処理したりすることもできます。 JavaScript のこれらの素晴らしい機能を理解することができれば、簡潔で強力なコードをたくさん書くことができます。
オブジェクトを置く
関数とオブジェクトの超越的な組み合わせを見てみましょう。
オブジェクト指向プログラミングの世界では、データとコードの有機的な組み合わせがオブジェクトの概念を構成します。オブジェクトが作成されて以来、プログラミングの世界は 2 つの部分に分割され、1 つはオブジェクト内の世界、もう 1 つはオブジェクトの外部の世界です。 オブジェクトは本質的に利己的であり、外部の世界は許可なしにオブジェクトの内部にアクセスすることはできません。オブジェクトには、外部の世界にプロパティとメソッドを提供し、他の人に役立つ寛大な側面もあります。しかし、ここで「対象の自己認識」という興味深い問題について話さなければなりません。
え?そうですか?対象者は自己認識していますか?
おそらく多くのプログラマにとって、これは実際に初めて聞いた言葉でしょう。ただし、これを C++、C#、Java で、self を DELPHI で、私を VB で見てください。もしかしたら、突然気づくかもしれません。もちろん、「それ以上は何もしない」ということも可能です。
しかし、物体が世界を内と外に分けるとき、物体の「自己」も現れます。 「自己認識」は人生の最も基本的な機能です!オブジェクトの強力な生命力があるからこそ、プログラミングの世界は無限の生命力と生命力に満ち溢れているのです。
しかし、その対象の「自己認識」は、私たちに幸福をもたらすだけでなく、苦しみや悩みももたらします。私たちは物に対してあまりにも多くの欲望を抱き、物がもっとできることを常に期待しています。ただし、オブジェクトの利己性によりシステム リソースをめぐって相互に競合し、オブジェクトの利己性によりオブジェクトが複雑かつ肥大化し、オブジェクトの自己欺瞞により長引くエラーや例外が発生することがよくあります。なぜ私たちはこれほどの痛みや悩みを抱えているのでしょうか?
この目的のために、オブジェクトの木の下で99日と81日考え続け、ついに人生の苦しみは欲望から来ているが、欲望の根源は自己認識から来ていることに気づいた人がいました。そこで彼は「我」を捨て、仏陀となり、衆生を救い、真実の経典を広めるようになりました。彼の名前は釈迦牟尼仏であり、彼の説いた経典の一つに『JavaScript経』があります。
JavaScriptにもこれがありますが、C++やC#、Javaなどの言語のこれとは異なります。一般的なプログラミング言語では、これはオブジェクトそのものですが、JavaScript では必ずしもそうではありません。これは私かもしれないし、あなたかもしれないし、彼かもしれません。とにかく、あなたは私の中にいて、私はあなたの中にいます。したがって、JavaScript ではこの意味を理解するために本来の「self」を使用することはできません。そのためには、まず元の対象である「自分」を手放す必要があります。
次のコードを見てみましょう:
function WhoAmI() //関数 WhoAmI を定義します
{
alert("I'm " + this.name + " of " + typeof(this));
};
WhoAmI(); //これは、この現在のコードのグローバル オブジェクトであり、ブラウザではウィンドウ オブジェクトであり、その name 属性は空の文字列です。出力: 私は対象です
var BillGates = {name: "Bill Gates"};
BillGates.WhoAmI = WhoAmI; //関数 WhoAmI を BillGates のメソッドとして使用します。
BillGates.WhoAmI(); //現時点ではこれは BillGates です。出力: 私はオブジェクト
の Bill Gates です
var SteveJobs = {name: "Steve Jobs"};
SteveJobs.WhoAmI = WhoAmI; // 関数 WhoAmI を SteveJobs のメソッドとして使用します。
SteveJobs.WhoAmI(); //現時点では SteveJobs です。出力: 私は object
の Steve Jobs です WhoAmI.call(BillGates); // BillGates をこれとして直接使用し、WhoAmI を呼び出します。出力: 私は object
の Bill Gates です WhoAmI.call(SteveJobs); // SteveJobs を直接使用して WhoAmI を呼び出します。出力: 私はオブジェクト
の Steve Jobs です。 BillGates.WhoAmI.call(SteveJobs); // SteveJobs をこのように使用しますが、BillGates の WhoAmI メソッドを呼び出します。出力: 私は object
の Steve Jobs です SteveJobs.WhoAmI.call(BillGates); // BillGates をこのように使用しますが、SteveJobs の WhoAmI メソッドを呼び出します。出力: 私はオブジェクトの Bill Gates です
WhoAmI.name = "WhoAmI";
WhoAmI.WhoAmI(); //現時点ではこれが WhoAmI 関数そのものです。出力: 私は function
({name: "nobody", WhoAmI: WhoAmI}).WhoAmI();出力: 私はオブジェクトの何者でもない
上記のコードからわかるように、同じ関数をさまざまな角度から呼び出すことができ、これは必ずしも関数自体が属するオブジェクトであるとは限りません。これは、オブジェクトを関数要素と組み合わせるときの単なる概念です。この組み合わせは、一般的なオブジェクト言語のデフォルトの組み合わせよりも柔軟であり、より独立していて自由に見えます。
JavaScript 関数では、現在提供されている「この」オブジェクトとしてのみこれをみなすことができます。これは特別な組み込みパラメータです。このパラメータに従って、「この」オブジェクトのプロパティとメソッドにアクセスできますが、このパラメータに値を割り当てることはできません。一般的なオブジェクト言語ではメソッド本体コード中のthisは省略可能で、デフォルトではメンバは先頭が「self」になります。ただし、JavaScript は異なります。「self」がないため、「this」オブジェクトにアクセスする場合、これを省略することはできません。
JavaScript はこのパラメーターを渡すさまざまな形式と手段を提供します。その中で、BillGates.WhoAmI() や SteveJobs.WhoAmI() などの形式が、現時点ではこのパラメーターを渡す最も正式な形式です。関数が属するオブジェクトそのもの。多くの場合、仙人や仏様から花を拝借する念仏の形はあまり使いません。ただし、JavaScript の「自分」は他のプログラミング言語の「自分」とは異なり、それが解放された「自分」であるということだけを理解してください。
オブジェクトスケッチ
多くのトピックについて話しましたが、議論するのを忘れていた非常に基本的な質問があります。それは、オブジェクトをどのように作成するかということです。
前の例では、すでにオブジェクトの作成が含まれています。私たちは JavaScript Object Notation (略称 JSON) と呼ばれる形式を使用します。これは中国語に翻訳すると「JavaScript Object Notation」となります。
JSON は、オブジェクトを作成するための非常に簡単な方法を提供します。たとえば、
プロパティを何も持たずにオブジェクトを作成します:var o = {};
オブジェクトを作成してプロパティと初期値を設定します:
オブジェクトを作成し、プロパティとメソッドを設定します:
他のオブジェクトをネストして、より複雑なオブジェクトを作成し、オブジェクト配列など:
{
名前: "Microsoft"、
製品: "ソフトウェア"、
会長: {名前: "ビル ゲイツ"、年齢: 53、既婚: true}、
従業員: [ {名前: "エンジェル"、年齢: 26、既婚: false}, {名前: "ハンソン"、年齢: 32、既婚者: true}],
readme: function() {document.write(this.name + " product " + this.product);}
};
JSON の形式は、中括弧「{}」で囲まれた項目のリストであり、各項目はカンマ「,」で区切られ、項目は属性名と属性値をコロン「:」で区切ったものになります。これは典型的な辞書表現であり、JavaScript のオブジェクトが辞書構造であることを再度示しています。オブジェクトがどれほど複雑であっても、JSON コードを使用して作成して割り当てることができます。
実際、JSON は JavaScript オブジェクトの最適なシリアル化形式であり、XML よりも簡潔でスペースを節約できます。オブジェクトを JSON 形式の文字列として使用して、ネットワーク間で情報を自由に送信および交換できます。この JSON 文字列を JavaScript オブジェクトに変換する必要がある場合は、eval 関数の強力なデジタル変換エンジンを使用するだけで、すぐに JavaScript メモリ オブジェクトを取得できます。 JSON の素朴で自然な美しさがあるからこそ、彼女は AJAX の舞台でまばゆいばかりのスターとなるのです。
JavaScriptはこのように、一見複雑に見えるオブジェクト指向を非常に簡潔な形で表現しています。パートナーの派手で濃いメイクを落として、澄んだ瞳をパートナーに与えましょう!
オブジェクトの構築
さて、オブジェクトを作成する別の方法について説明しましょう。
JSON に加えて、JavaScript では関数と組み合わせた new 演算子を使用してオブジェクトを作成できます。例:
function MyFunc() {}; // 空の関数を定義します
var anObj = new MyFunc() // new 演算子を使用し、MyFun 関数を使用してオブジェクトを作成します
JavaScript でオブジェクトを作成する方法この書き方は本当に興味深いです。
実際、上記のコードは次の同等の形式に書き直すことができます:
function MyFunc(){};
var anObj = {}; //オブジェクトを作成します
MyFunc.call(anObj) //Obj オブジェクトを作成します。 MyFunc 関数をこのポインターとして使用します
このように理解できます。JavaScript はまず new 演算子を使用してオブジェクトを作成し、次にこのオブジェクトを this パラメーターとして使用して次の関数を呼び出します。実際、これは JavaScript が内部的に行っていることであり、どの関数もこのように呼び出すことができます。しかし、「anObj = new MyFunc()」の形式から、これが C++ と C# のオブジェクトの作成方法であることがわかります。すべての道は霊山に通じており、同じ目的地に通じていることが分かりました。
これを見て、なぜこの MyFunc をコンストラクターとして使用できないのかと思うかもしれません。おめでとうございます。わかりました! JavaScript もそう考えています。以下のコードを見てください:
1 function person(name) // パラメーターを持つコンストラクター
2 {
3 this.name = name // このオブジェクトのプロパティにパラメーター値を割り当てます
4 this.SayHello = function; () {alert("Hello, I'm " + this.name);}; // このオブジェクトの SayHello メソッドを定義します。
5 };
6
7 function Employee(name,給与) //サブコンストラクタ
8 {
9 person.call(this, name) // これを親コンストラクタに渡します
10 this.salary =給与 ;
12 };
13
14 var BillGates = new Person("Bill Gates") // Person コンストラクターを使用して BillGates オブジェクトを作成します
15 var SteveJobs = new Employee("Steve Jobs", 1234); Empolyee コンストラクター この関数は SteveJobs オブジェクトを作成します
16
17 BillGates.SayHello(); //Show: I'm Bill Gates
18 SteveJobs.SayHello(); //Show: I'm Steve Jobs
19 SteveJobs.ShowMeTheMoney (); // 表示: スティーブ ジョブズ $1234
20
21 アラート(BillGates.constructor == 人) // 表示: true
22 アラート(SteveJobs.constructor == 従業員); // 表示: true
23
24 alert(BillGates.SayHello == SteveJobs.SayHello); //表示: false
このコードは、関数がコンストラクターとして使用できるだけでなく、パラメーターを受け取り、メンバーやメソッドをオブジェクトに追加できることを示しています。 9 行目で、Employee コンストラクターは、パラメーターとして受け取った this を使用して Person コンストラクターを呼び出します。これは、基本クラスのコンストラクターを呼び出すのと同じです。行 21 と行 22 は、次のことも示しています。BillGates は person から構築され、SteveJobs は Employee から構築されます。オブジェクトの組み込みコンストラクター プロパティは、オブジェクトの構築に使用される特定の関数も指定します。
実際、関数を「クラス」として考える場合、それはすでに「クラス」の特性を備えているため、「クラス」です。そうではありませんか?彼女が産んだ息子は皆同じ特性を持ち、コンストラクターもクラス名と同じ!
ただし、このオブジェクトを操作するコンストラクターを使用して作成された各オブジェクトには、独自のメンバー データだけでなく、独自のメソッド データもあることに注意してください。つまり、メソッドのコード本体 (関数ロジックを具体化するデータ) のコピーが各オブジェクト内にあります。各コード コピーのロジックは同じですが、オブジェクトはそれぞれコード本体のコピーを保存します。上記の例の最後の文はこの事実を示しており、JavaScript のオブジェクトとしての関数の概念も説明しています。
同じクラスのオブジェクトがそれぞれメソッド コードを持つのは明らかに無駄です。従来のオブジェクト言語では、メソッド関数は JavaScript のようなオブジェクト概念ではありません。関数ポインター、メソッド ポインター、デリゲートなどのバリエーションはありますが、基本的には同じコードへの参照です。一般的なオブジェクト言語ではこの状況に遭遇することは困難です。
ただし、JavaScript 言語には優れた柔軟性があります。最初に固有のメソッド関数本体を定義し、このオブジェクトを構築するときにこの固有の関数オブジェクトをそのメソッドとして使用することで、メソッドのロジックを共有できます。例:
function SayHello() // 最初に SayHello 関数のコードを定義します
{
alert("Hello, I'm " + this.name);
};
function Person(name) // パラメーターを使用した構築 Function {{i this.name = name; // このオブジェクトの属性にパラメータ値を割り当てます www.2cto.com
this.sayhello = Sayhello; // このオブジェクトに対する Sayhello メソッドの値は、前の Sayhello;コード。
};
var BillGates = new Person("Bill Gates"); //BillGates オブジェクトを作成します
alert(BillGates.SayHello == SteveJobs) .SayHello); //Display: true
このうち、最後の行の出力結果は、2 つのオブジェクトが関数オブジェクトを共有していることを示しています。このプログラムはメソッド コードを共有するという目的は達成していますが、あまりエレガントではありません。それは、SayHello メソッドの定義が Person クラスとの関係を反映していないためです。 「エレガント」という言葉はコードを表すのに使われますが、誰が最初にそれを提案したのかはわかりません。しかし、この言葉は、プログラマーがコードの正確さ、効率性、信頼性、読みやすさの追求から、コードの美的感覚と芸術的領域の追求へと発展し、プログラミング生活がよりロマンチックになったことを反映しています。
明らかに、JavaScript はこの問題をすでに考えており、その設計者はこれに対する興味深いプロトタイプのコンセプトを提供しています。
プロトタイプの初見
プロトタイプはフランス語から来ており、ソフトウェア業界での標準的な翻訳は「プロトタイプ」で、物事の初期の形を表し、モデルやテンプレートの意味も含まれています。 JavaScript のプロトタイプの概念は、この言葉の意味を適切に反映しています。これを、C++ で事前に宣言されたプロトタイプの概念として理解することはできません。
JavaScript のすべての関数型オブジェクトには、prototype 属性があります。プロトタイプ属性自体はオブジェクト型のオブジェクトであるため、このプロトタイプ オブジェクトに任意のプロパティとメソッドを追加することもできます。プロトタイプはオブジェクトの「プロトタイプ」であるため、この関数によって構築されるオブジェクトはこの「プロトタイプ」特性を持つ必要があります。実際、コンストラクターのプロトタイプで定義されたすべてのプロパティとメソッドは、それが構築するオブジェクトを通じて直接アクセスして呼び出すことができます。プロトタイプは、同様のオブジェクトのグループがプロパティとメソッドを共有するためのメカニズムを提供するとも言えます。
まず次のコードを見てみましょう:
function Person(name)
{
this.name = name; //オブジェクトの属性を設定します。各オブジェクトには独自の属性データがあります
};
Person.prototype.SayHello = function() //SayHello メソッドを Person 関数のプロトタイプに追加します。 Er {
Alert ("Hello, I'm" + this.Name);
} var Billgates = New Person ("Bill Gates") // Billgates オブジェクトを作成します
Var Stevejobs = New Person("Steve Jobs) " "" ; = SteveJobs.SayHello); // 2 つのオブジェクトはプロトタイプを共有する SayHello であるため、 true と表示されます
プログラムの実行結果は、コンストラクターのプロトタイプで定義されたメソッドが実際にオブジェクトを通じて直接呼び出され、コードが共有されます。明らかに、メソッドをプロトタイプに設定する記述方法は、呼び出し形式に変更はありませんが、以前の記述方法と比較して、メソッドとクラスの関係を論理的に反映しています。コード。
もう一度次のコードを見てみましょう:
2 {
3 this.name = name;4 };
56 person.prototype.SayHello = function() // 基本構成関数に proprope メソッドを追加します
7 { 8 Alert ("Hello, I'm" + This.name)
9}; // 基本構造関数を呼び出します
14 this.salar = pay;
15}; これは非常に興味深いものです。メソッドをサブクラス コンストラクターのプロトタイプに追加します。 / 基本クラス Person の BillGates オブジェクトを作成します
25 var SteveJobs = new Employee("Steve Jobs", 1234) // サブクラス Employee の SteveJobs オブジェクトを作成します
26
27 BillGates.SayHello(); //オブジェクトを介して直接プロトタイプ メソッドを呼び出す
28 SteveJobs.SayHello(); // サブクラス オブジェクトを介して直接、基本クラスのプロトタイプのメソッドを呼び出すことに注意してください。
29 SteveJobs.ShowMeTheMoney(); //サブクラス オブジェクトを通じてサブクラス プロトタイプのメソッドを直接呼び出します
30
31 alter(BillGates.SayHello == SteveJobs.SayHello) //プロトタイプ メソッドが共有
このコードの 17 行目では、基本クラス オブジェクトが構築され、サブクラス コンストラクターのプロトタイプとして設定されています。これは非常に興味深いです。この目的は 28 行目です。基本クラスのプロトタイプのメソッドは、サブクラス オブジェクトを通じて直接呼び出すこともできます。なぜこのようなことが可能なのでしょうか?
JavaScript では、プロトタイプによってオブジェクトがその富を共有できるだけでなく、プロトタイプにはそのルーツや祖先をたどるという性質もあり、先祖の遺産を世代から世代へと受け継ぐことができることがわかりました。オブジェクトから属性を読み取るかメソッドを呼び出す場合、オブジェクト自体にそのような属性やメソッドがない場合は、それ自体に関連付けられているプロトタイプ オブジェクトに移動して検索します。プロトタイプに属性やメソッドがない場合は、先行するオブジェクトに移動します。プロトタイプ自体に関連付けられたプロトタイプが見つかるまで、またはトレース プロセスが完了するまで検索します。
JavaScript 内では、オブジェクトの属性とメソッドのトレース メカニズムが、いわゆるプロトタイプ チェーンを通じて実装されます。 new 演算子を使用してオブジェクトが構築されると、コンストラクターのプロトタイプ オブジェクトも新しく作成されたオブジェクトに割り当てられ、オブジェクトの組み込みプロトタイプ オブジェクトになります。オブジェクトの組み込みプロトタイプ オブジェクトは外部からは見えないようにする必要がありますが、一部のブラウザ (Firefox など) ではこの組み込みプロトタイプ オブジェクトにアクセスできますが、これはお勧めできません。組み込みプロトタイプ オブジェクト自体もオブジェクトであり、独自の関連付けられたプロトタイプ オブジェクトを持ち、いわゆるプロトタイプ チェーンを形成します。
プロトタイプ チェーンの最後にあるのは、オブジェクト コンストラクターのプロトタイプ属性によって指されるプロトタイプ オブジェクトです。このプロトタイプ オブジェクトは、すべてのオブジェクトの最も古い祖先であり、すべてのオブジェクトが本質的に持つべき toString などのメソッドを実装します。 Function、Boolean、String、Date、RegExp などの他の組み込みコンストラクターのプロトタイプはすべてこの祖先から継承されていますが、それらはそれぞれ独自のプロパティとメソッドを定義しているため、子孫はそれぞれのクランの特性を示します。それらの特徴。
これは「相続」ではないでしょうか?そう、これが「継承」、JavaScript特有の「プロトタイプ継承」です。
「原型継承」は優しくて厳しい。プロトタイプ オブジェクトは、そのプロパティとメソッドを無私無欲に子供たちに提供し、子供たちに従うことを強制しないため、一部のいたずらな子供たちが自分の興味や趣味に応じて独立して行動できるようになります。この点において、典型的な主体は愛情深い母親です。ただし、どの子供も自分のやり方を貫くことができますが、他の子供の利益に影響を与える可能性があるため、プロトタイプ オブジェクトの既存のプロパティに触れることはできません。 この観点から見ると、プロトタイプオブジェクトは厳格な父親のようなものです。これが何を意味するのかを理解するために、次のコードを見てみましょう:
function Person(name)
{
this.name = name;
};
Person.prototype.company = "Microsoft" //プロトタイプ プロパティ
; Person.prototype.SayHello = function() //プロトタイプメソッド
{
alert("こんにちは、" + this.name + " of " + this.company);
};
var BillGates = new Person( "Bill Gates");
BillGates.SayHello(); // プロトタイプを継承しているため、出力は通常です: こんにちは、私は Bill Gates です
var SteveJobs = new Person("Steve Jobs"); company = "Apple" //プロトタイプの会社プロパティをマスクして、独自の会社プロパティを設定します
SteveJobs.SayHello = function() //プロトタイプの SayHello メソッドをマスクして、独自の SayHello メソッドを実装します
{
アラート ("こんにちは、 " + this.name + " like " + this.company + ", ha ha ha ");
};
SteveJobs.SayHello(); // これらはすべて、それ自体でカバーされるプロパティとメソッドです、出力: こんにちは、スティーブApple のようなジョブ、ハハハ
BillGates.SayHello(); // SteveJobs のオーバーライドはプロトタイプ オブジェクトに影響を与えず、BillGates は以前と同じ出力を継続します
オブジェクトはプロトタイプ オブジェクト、コンストラクターのプロパティとメソッドをマスクできますプロトタイプ オブジェクトは、上位レベルのコンストラクター プロトタイプ オブジェクトの既存のプロパティとメソッドをマスクすることもできます。このマスキングは実際にはオブジェクト自体に新しいプロパティとメソッドを作成するだけですが、これらのプロパティとメソッドはプロトタイプ オブジェクトの名前と同じです。 JavaScript は、この単純なマスキング メカニズムを使用してオブジェクトの「ポリモーフィズム」を実現します。これは、静的オブジェクト言語の仮想関数およびオーバーライドの概念と一致します。
ただし、静的オブジェクト言語よりもさらに素晴らしいのは、プロトタイプ オブジェクトにいつでも新しいプロパティとメソッドを動的に追加できるため、基本クラスの機能機能を動的に拡張できることです。これは静的オブジェクト言語では想像するのが困難です。次のコードを見てみましょう:
function Person(name)
{
this.name = name;
};
person.prototype.SayHello = function() //オブジェクトを作成する前に定義されたメソッド
{
alert("こんにちは、私は " + this.name);
};
var BillGates = new Person("Bill Gates"); // オブジェクトを作成します
BillGates.SayHello();
Person.prototype.Retire = function () //オブジェクト作成後にプロトタイプを動的に拡張するメソッド
{
alert("Poor " + this.name + ", bye bye!");
};
BillGates.Retire();拡張 以前に作成したオブジェクトからメソッドをすぐに呼び出すことができます
阿弥陀さま、プロトタイプの継承は実際にそのような魔法を実行できます!
プロトタイプの拡張
あなたは次のように考えるかもしれません: Object や Function などの JavaScript の組み込み関数のプロトタイプに新しいメソッドやプロパティを追加すると、その機能を拡張できるでしょうか。ジャバスクリプト?
おめでとうございます、わかりました!
現在、AJAX テクノロジーの急速な発展に伴い、多くの成功した AJAX プロジェクトの JavaScript ランタイム ライブラリは、組み込み関数のプロトタイプ関数を大幅に拡張しています。たとえば、Microsoft の ASP.NET AJAX は、これらの組み込み関数とそのプロトタイプに多数の新機能を追加し、JavaScript の機能を強化します。
MicrosoftAjax.debug.js から抜粋したコードを見てみましょう:
String.prototype.trim = function String$trim() {
if (arguments.length !== 0) throw Error.parameterCount();
return this.replace(/^s+|s+$/g, '');
}
このコードは、trim メソッドを組み込み String 関数のプロトタイプに拡張するため、すべての String クラス オブジェクトが trim メソッドを持ちます。この拡張機能を使用すると、将来、文字列の 2 つのセクション間の空白を削除したい場合、それを個別に処理する必要がなくなりました。どの文字列にもこの拡張機能があり、それを呼び出すだけで済むためです。便利。
もちろん、アーキテクチャ内のすべてのオブジェクトで実際にこのメソッドが必要な場合を除き、Object のプロトタイプにメソッドを追加する人はほとんどいません。これはすべてのオブジェクトに影響するからです。
2 年前、AJAX クラス ライブラリの設計の初期段階で、Microsoft は「クラス」をシミュレートするために「クロージャ」と呼ばれるテクノロジを使用しました。ラフモデルは次のとおりです。 'm " + firstName + "" + LastName);
Var ビルゲイツ = 新しい人 (" ビル "," ゲイツ ", 53); ," ジョブ ", 53) ;
BillGates.SayHello();
alert(BillGates.getName() + " " + BillGates.age);
alert(BillGates.firstName);ここではプライベート変数にはアクセスできません
このモデルのクラス記述は、特に C# 言語の記述形式に似ており、コンストラクター内でプライベート メンバー、パブリック プロパティ、利用可能なメソッドが連続して定義されていることがわかります。特に、「クロージャ」メカニズムはプライベート メンバーの保護メカニズムをシミュレートでき、非常に美しいです。
いわゆる「クロージャ」とは、コンストラクタ本体に別の関数を対象オブジェクトのメソッド関数として定義し、そのオブジェクトのメソッド関数が外側の関数本体の一時変数を参照することです。これにより、ターゲット オブジェクトが存続期間中常にそのメソッドを維持できる限り、元のコンストラクター本体で使用される一時変数の値を間接的に維持できます。最初のコンストラクター呼び出しが終了し、一時変数の名前が消えていますが、変数の値はターゲット オブジェクトのメソッド内で常に参照でき、このメソッドを介してのみ値にアクセスできます。同じコンストラクターが再度呼び出された場合でも、新しいオブジェクトとメソッドのみが生成され、新しい一時変数は最後の呼び出しから独立した新しい値にのみ対応します。確かにとても賢いですね!
しかし、前に述べたように、オブジェクトごとにメソッドを設定するのは大きな無駄です。さらに、変数値を間接的に維持するメカニズムである「クロージャ」は、JavaScript のガベージ コレクターに問題を引き起こすことがよくあります。特にオブジェクト間の複雑な循環参照が発生した場合、ガベージコレクションの判定ロジックは非常に複雑になります。偶然にも、IE の初期バージョンでは JavaScript ガベージ コレクションでメモリ リークが発生しました。パフォーマンス テストにおける「クロージャ」モデルのパフォーマンスの低さと相まって、Microsoft は最終的に「クロージャ」モデルを放棄し、「プロトタイプ」モデルに切り替えました。ことわざにあるように、「得たものには必ず損失が伴います」。
プロトタイプ モデルにはオブジェクトのメンバーを定義するコンストラクターが必要ですが、メソッドはコンストラクターのプロトタイプにアタッチされます。大まかな書き方は次のとおりです。
//コンストラクターを定義します
function Person(name)
{
this.name = name; // コンストラクター内のメンバーを定義します };
// メソッドは、コンストラクター
person .prototype.SayHello = function()
// call(this, name);上位コンストラクター
this.salary =給与; //拡張メンバー
};
//サブクラス コンストラクターは最初に次のことを行う必要があります。上部のコンストラクターを使用してプロトタイプ オブジェクトを作成し、継承を実装します。 Concept
Employee.prototype = new Person() //プロトタイプのメソッドのみが必要で、このオブジェクトのメンバーには意味がありません。子 // サブクラス メソッドは構成関数でも定義されています
employee.prototype.showmetheMoney = function () {
alert (this.Name + "$" + this.salary)
}
Gates = new person ("Bill Gates");
BillGates.SayHello();
var SteveJobs = new Employee("Steve Jobs", 1234);
SteveJobs.SayHello();
SteveJobs.ShowMeTheMoney();
プロトタイプ クラス モデル実際のプライベート変数をシミュレートすることはできず、クラスは 2 つの部分に分けて定義する必要があるため、あまり「エレガント」とは思えません。ただし、メソッドはオブジェクト間で共有され、ガベージ コレクションの問題が発生せず、「クロージャ」モデルよりも優れたパフォーマンスを発揮します。ことわざにあるように、「失うものは必ず得られるものである」。
プロトタイプ モデルでは、クラスの継承を実装するために、まずサブクラス コンストラクターのプロトタイプを親クラスのオブジェクト インスタンスに設定する必要があります。この親クラスのオブジェクト インスタンスを作成する目的は、上位のプロトタイプ メソッドを共有するプロトタイプ チェーンを形成することです。ただし、このインスタンス オブジェクトが作成されると、上位レベルのコンストラクターもオブジェクト メンバーをそれに設定します。これらのオブジェクト メンバーは継承には意味がありません。コンストラクターにパラメーターを渡していないにもかかわらず、値が未定義であるにもかかわらず、役に立たないメンバーが多数作成されてしまい、これも無駄です。
ああ!世の中に完璧なものなどありません!
原型の真実
私たちが感無量に陥ったそのとき、空に赤い光が点滅し、吉祥の雲の中に観音菩薩が現れました。彼女が翡翠の浄化瓶を持ち、緑の柳の枝をはじき、蜜を数滴振りかけているのを見たとき、すぐに JavaScript に新しいオーラが与えられました。
観音様が撒いた蜜は、JavaScriptの世界ではブロックに凝縮され、「文法蜜」と呼ばれるものになりました。この構文の蜜により、私たちが書くコードがよりオブジェクト言語のように見えるようになります。
この「文法蜜」が何なのか知りたい方は、よく聞いてください。
これらの文法的な要点を理解する前に、JavaScript でオブジェクトを構築するプロセスを確認する必要があります。
var anObject = new aFunction() の形式でオブジェクトを作成するプロセスは、実際には 3 つのステップに分割できることはすでにわかっています。最初のステップは、新しいオブジェクトを作成することです。2 番目のステップは、構築されたオブジェクトを設定することです。コンストラクターとしてのオブジェクトのプロトタイプ オブジェクトで、prototype によって参照されるプロトタイプ オブジェクト。3 番目のステップでは、オブジェクトをこのパラメーターとして使用してコンストラクターを呼び出し、メンバーの設定などの初期化作業を完了します。オブジェクトの作成後、オブジェクトに対するアクセスと操作は、オブジェクト自体とプロトタイプ チェーン上のオブジェクトの文字列にのみ関連し、コンストラクターとは何の関係もありません。つまり、コンストラクターはオブジェクト作成時にプロトタイプオブジェクトの導入と初期化の役割だけを果たします。
では、自分でオブジェクトをプロトタイプとして定義し、そのプロトタイプ上にクラスを記述し、そのプロトタイプを新しく作成したオブジェクトに設定して、そのオブジェクトのクラスとして扱うことができるのでしょうか?このプロトタイプのメソッドをコンストラクターとして使用して、新しく作成されたオブジェクトを初期化できますか?たとえば、次のようなプロトタイプ オブジェクトを定義します。
var person = //オブジェクトをプロトタイプ クラスとして定義します
{
Create: function(name, age) // これがコンストラクターです
.age = 年齢;
},
SayHello: function()
{T アラート (this.name + "is" + this.age + "" year old. ");
}}};
この JSON フォームは C#class に似ています。コンストラクターとさまざまなメソッドの両方があります。何らかの形式でオブジェクトを作成し、そのオブジェクトの組み込みプロトタイプを上記の「クラス」オブジェクトに設定できれば、そのクラスのオブジェクトを作成するのと同じではないでしょうか。
しかし、残念ながら、オブジェクトに組み込まれたプロトタイプのプロパティにはほとんどアクセスできません。一部のブラウザはオブジェクトの組み込みプロトタイプにアクセスできますが、これにより、ユーザーが使用しなければならないブラウザが制限されるだけです。これもほぼ不可能です。
では、関数オブジェクトを媒介として、関数オブジェクトのprototype属性を使ってプロトタイプを渡し、new演算子を使って新しく作成したオブジェクトに渡すことはできるのでしょうか?
実際、次のようなコードでこの目標を達成できます:
function anyfunc(){}; // 関数シェルを定義します
anyfunc.prototype = Person // プロトタイプ オブジェクトを転送ステーションのプロトタイプに配置します