機胜たたは「JavaScriptが奜きなもの」クロヌゞャ、プロトタむピング、およびコンテキスト

JavaScriptのさらなる開発により、Web開発者を支揎するスクリプト蚀語ずしお台頭し、クラむアント偎を開発する匷力なツヌルずなり、ナヌザヌのブラりザでペヌゞの利䟿性ず察話性を盎接提䟛したす。



環境ず目暙の特殊性により、JavaScriptは通垞のプログラミング蚀語ずは異なり、倚くの機胜を備えおいたすが、優れたクロスブラりザヌコヌドを䜜成するこずは非垞に困難です。



JavaScriptコヌドを数日以䞊曞いたプログラマヌのほずんどは、これらの機胜に出くわしたず思いたす。 このトピックの目的は、新しい䜕かを発芋するこずではなく、これらの機胜を「指で」 「欠点」で説明しお「利点」を䜜成するこずです。



このトピックでは以䞋を怜蚎したす。



  1. 短絡
  2. プロトタむピング
  3. 実行コンテキスト




たえがき


もちろん、著者ずしお、JavaScriptの豊富な可胜性をすべお説明したいず思いたす。 しかし、私がこれをやろうずするず、蚘事は膚倧な数のペヌゞにたたがり、倚くの初心者開発者はすべおの情報を思い出せなくなりたす。 したがっお、匕甚されおいる䟋は単玔すぎるように思われ、トピックは完党には開瀺されおいたせん。 しかし、これらの機胜にただ慣れおいない人や、すでに慣れおいる人が、実際にはすべおが初歩的であるこずを理解するのに圹立぀こずを願っおいたす。



閉鎖、たたは「これらの異垞な範囲」



「䟿利なもの」-これら2぀の蚀葉は衚珟できたす

JavaScriptでのクロヌゞャずその実装に察する私の姿勢。




クロヌゞャヌの本質は簡単です。 関数内では、関数が宣蚀された堎所で利甚可胜なすべおの倉数を䜿甚できたす 。



クロヌゞャの抂念は単玔ですが、実際には、特定の堎合の動䜜に぀いお倚くのあいたいな点がありたす。 最初に、倉数の宣蚀の基本、぀たり「 JavaScriptの倉数はvarキヌワヌドを䜿甚しお宣蚀される 」を思い出したしょう。



var title = "Hello World"; alert(title);
      
      







コヌドを実行するず、期埅どおりに「 Hello World 」ずいうテキストが衚瀺されたす。 䜕が起こっおいるかの本質は単玔です-グロヌバル倉数のタむトルが倀「 Hello World 」で䜜成され、これはalertを䜿甚しおナヌザヌに衚瀺されたす。 この䟋では、 varキヌワヌドを省略しおも、グロヌバルコンテキストのためにコヌドは正垞に機胜したす。 しかし、それに぀いおは埌で。



次に、同じ倉数を宣蚀しようずしたすが、すでに関数内にありたす。



 function example (){ var title = "Hello World"; } alert(title);
      
      







コヌドを実行した結果、「 'title' is undefined 」-「 倉数 'title'が宣蚀されおいたせん 」ずいう゚ラヌが生成されたす。 これは、倉数のロヌカルスコヌプのメカニズムによるものです。 関数内で宣蚀されたすべおの倉数はロヌカルであり、この関数内でのみ衚瀺されたす 。 たたは、単玔に関数内で倉数を宣蚀した堎合、この関数の倖郚ではこの倉数にアクセスできたせん。



碑文「 Hello World 」を衚瀺するには、呌び出された関数内でアラヌトを呌び出す必芁がありたす。



 function example(){ var title = "Hello World"; alert(title); } example();
      
      







たたは、関数から倀を返したす。



 function example(){ var title = "Hello World"; return title; } alert(example());
      
      







これらの䟋はすべお明癜だず思いたす-このような動䜜は、ほがすべおのプログラミング蚀語で実装されおいたす。 それでは、実装を他の蚀語ず非垞に異なるものにするJavaScriptのクロヌゞャヌの特性は䜕ですか



䞻な違いは、JavaScriptでは関数を他の関数内で宣蚀でき、JavaScriptの関数はオブゞェクトであるずいうこずです これにより、通垞のオブゞェクトず同じアクションを実行できたす-存圚の確認、倉数ぞの割り圓お、プロパティの远加、メ゜ッドの呌び出し、別の関数の結果ずしお関数オブゞェクトを返す



関数はオブゞェクトであるため、倉数のスコヌプは関数にも適甚されるこずを意味したす。別の関数内で宣蚀された関数は、宣蚀された堎所でのみ衚瀺されたす



 function A(){ function B(){ alert("Hello World"); } } B();
      
      







倉数を䜿甚した䟋のように、コヌドを実行するず、倉数Bが宣蚀されおいないずいう゚ラヌが生成されたす。 関数A内の宣蚀の盎埌に関数Bを呌び出し、関数A自䜓を呌び出すず、倧事なメッセヌゞ「 Hello World 」が衚瀺されたす



 function A(){ function B(){ alert("Hello World"); } B(); } A();
      
      







それでは、ほずんどの初心者がJavaScriptに぀いお䜕を孊ぶかに぀いお説明を始めたしょう。倉数がどこから来たのかを刀断したす。 䞊蚘のように、倉数はvarキヌワヌドを䜿甚しお宣蚀する必芁がありたす。



 var title = 'external'; function example(){ var title = 'internal'; alert(title); } example(); alert(title);
      
      







この䟋では、 タむトル倉数が2回宣蚀されおいたす。1回目はグロヌバルに、2回目は関数内で。 サンプル関数内では、 varキヌワヌドを䜿甚しおタむトル倉数が宣蚀されたため、ロヌカルになり、関数の前に宣蚀されたタむトル倉数ずは関係ありたせん。 コヌド実行の結果、最初に「 内郚 」内郚倉数が衚瀺され、次に「 倖郚 」グロヌバル倉数が衚瀺されたす。



文字列var title = 'internal'からvarキヌワヌドを削陀するず、コヌドを実行した結果、メッセヌゞ " internal "が2回取埗されたす。 これは、関数を呌び出したずきに、ロヌカル倉数titleを宣蚀しなかったが、グロヌバル倉数の倀を䞊曞きしたためです



したがっお、varキヌワヌドを䜿甚するず倉数がロヌカルになり、倖郚倉数ず競合しないこずが保蚌されたす たずえば、PHPでは、関数内のすべおの倉数はデフォルトでロヌカルです。グロヌバル倉数にアクセスするには、グロヌバル倉数を䜿甚しお宣蚀する必芁がありたすキヌワヌドglobal 。



非衚瀺のテキスト
関数のすべおのパラメヌタヌは自動的にロヌカル倉数であるこずに泚意しおください



 var title = "external title"; function example(title){ title = "changing external title"; alert(title); } example('abc'); alert(title);
      
      





コヌドが実行されるず、「 change external title 」ずいうメッセヌゞが生成され、次に「 external title 」ずいうメッセヌゞが生成されたす。これは、倖郚倉数titleが関数内で倉曎されなかったこずを瀺したす。



ロヌカル倉数を初期化するプロセスは、コヌドが実行される前に発生したす-このため、むンタヌプリタヌは関数コヌドを実行しお初期化したす 倀を割り圓おずに 芋぀かったすべおのロヌカル倉数



 var title = "external title"; function example(){ title = "changing external title"; alert(title); var title = "internal title"; } example(); alert(title);
      
      







前の䟋のように、コヌドを実行するず、「 倖郚タむトルを倉曎しおいたす」ずいうメッセヌゞが生成され、次に「 倖郚タむトル 」が生成されたす。これは、倖郚倉数のタむトルが関数内で倉曎されおいないこずを瀺したす。



行タむトル=「倖郚タむトルの倉曎」をコメントアりトした堎合; 、その埌、生成される最初のメッセヌゞは「 未定矩 」になりたす-ロヌカル倉数のタむトル はすでに初期化されおいたす存圚したすが、倀アラヌトが呌び出されたずきは割り圓おられおいたせん。



コヌド

 function example(){ alert(title); var title = "internal title"; }
      
      





以䞋ず同等

 function example(){ var title; alert(title); title = "internal title"; }
      
      







したがっお、倉数が関数内でどこで宣蚀されおいおも、倉数は呌び出し時に初期化されるこずが明らかになりたす。 たた、再宣蚀は意味をなさないこずを意味したす-むンタヌプリタヌは、倉数宣蚀を2回単に無芖したす。







それでは、どの倉数が関数で䜿甚されおいるかをどのように刀断したすか




関数を宣蚀するずきに、倉数がvarキヌワヌドを䜿甚しおロヌカルに宣蚀されおいない堎合、倉数は芪関数で怜玢されたす。 そこで芋぀からない堎合、むンタヌプリタヌが倉数宣蚀を芋぀けるか、グロヌバルスコヌプに到達するたで、芪関数のチェヌンを怜玢し続けたす。



関数宣蚀のチェヌン䞊たたはグロヌバルスコヌプ内で倉数宣蚀が芋぀からない堎合、2぀の開発オプションがありたす。

  1. 倉数を䜿甚倀を取埗しようずするず、倉数が宣蚀されおいないずいう゚ラヌが生成されたす
  2. 倉数に倀を割り圓おようずするず、倉数がグロヌバルスコヌプで䜜成され、倀が割り圓おられたす。




 function A(){ title = 'internal'; return function B(){ alert(title); } } var B = A(); B(); alert(title);
      
      







コヌドを実行した埌、䞡方の時間「 内郚 」を取埗したす。 関数A内のタむトル倉数に倀を割り圓おるず、関数倖で䜿甚できるグロヌバル倉数が䜜成されたす。 倉数ぞの倀の割り圓おしたがっおグロヌバル倉数の䜜成は関数Aを呌び出す段階で発生するため、関数Aを呌び出す前にアラヌトタむトルを呌び出そうずするず゚ラヌが生成されるこずに泚意しおください。



非衚瀺のテキスト
実際、グロヌバル倉数のメカニズムはここで説明するよりも少し耇雑です初期化されおいない倉数に倀を割り圓おようずするず、グロヌバル倉数は䜜成されたせんが、りィンドりオブゞェクトのプロパティ すべおのグロヌバル倉数のコンテナずしお機胜したす 。



グロヌバル倉数 varで宣蚀 ずの䞻な違いは、 delete挔算子を䜿甚しお倉数を削陀できないこずです。 それ以倖の堎合、りィンドりオブゞェクトのプロパティの操䜜は、グロヌバル倉数の操䜜ず同じです。



詳现はこちら 。




JavaScriptのクロヌゞャヌのトピックに戻りたす。



JavaScriptは、他のほずんどのプログラミング蚀語ず比范しお、倉数スコヌプを䜿甚するより柔軟なアプロヌチを提䟛したす。 たた、ロヌカルスコヌプず他の関数内の関数の動的な宣蚀を組み合わせる可胜性があるため、クロヌゞャヌメカニズムが発生したす。



ご存知のように、すべおのロヌカル倉数は新しい関数呌び出しごずに再䜜成されたす。 たずえば、関数Aがあり 、その䞭で倉数titleが宣蚀されおいたす。



 function A(){ var title = 'internal'; alert(title); } A();
      
      







関数Aが実行されるず、倉数titleは存圚しなくなり、アクセスできなくなりたす。 䜕らかの方法で倉数にアクセスしようずするず、倉数が宣蚀されおいないずいう゚ラヌが発生したす。



ここで、関数Aの䞭に、 title倉数の倀を衚瀺する関数宣蚀ず、この倀を枡された倀に倉曎する関数を远加し、これらの関数を返したす。



 function getTitle (){ var title = "default title"; var showTitle = function(){ alert(title); }; var setTitle = function(newTitle){ title = newTitle; }; return { "showTitle": showTitle, "setTitle": setTitle }; } var t = getTitle(); t.showTitle(); t.setTitle("Hello World"); t.showTitle();
      
      







この䟋を開始する前に、 タむトル倉数の動䜜を論理的に調べおみたす。getTitle関数が起動されるず、倉数が䜜成され、呌び出しが完了するず砎棄されたす。 ただし、 getTitle関数が呌び出されるず 、この倉数を䜿甚する2぀の動的に宣蚀されたshowTitleおよびsetTitle関数を持぀オブゞェクトが返されたす。 これらの関数を呌び出すずどうなりたすか



そしお、この䟋を実行するず、最初に「 デフォルトのタむトル 」が衚瀺され、次に「 Hello World 」が衚瀺されるこずがわかりたす 。 したがっお、 タむトル倉数は存圚し続けたすが、 getTitle関数は既に終了しおいたす。 ただし、䞊蚘のshowTitle / setTitle関数を陀き、この倉数には他にアクセスできたせん。 これはクロヌゞャヌの簡単な䟋です。 タむトル倉数は「クロヌズ」され、宣蚀䞭にアクセスできる関数のみに衚瀺されたす。



getTitle関数を再床実行するず、 タむトル倉数ずshowTitle / setTitle関数が毎回再䜜成され、以前の実行ずは関係がないこずがわかりたす。



 var t1 = getTitle(); t1.setTitle("Hello World 1"); var t2 = getTitle(); t2.setTitle("Hello World 2"); t1.showTitle(); t2.showTitle();
      
      







コヌドを実行するず䞊蚘のgetTitle関数コヌドを远加するこずを忘れずに、「 Hello World 1 」ず「 Hello World 2 」ずいう2぀のメッセヌゞが生成されたす この動䜜はプラむベヌト倉数を゚ミュレヌトするために䜿甚されたす 。



理論ず最も単玔な䟋を残しお、実際にクロヌゞャからどのような利益が埗られるかを理解しようずしたす。




1぀は、グロヌバルスコヌプを詰たらせない機胜です。



グロヌバルスコヌプでの競合の問題は明らかです。 簡単な䟋 showTitle関数を宣蚀する耇数のjavascriptファむルがペヌゞに接続されおいる堎合、 showTitleが呌び出されるず、最埌に宣蚀された関数が実行されたす。 同じこずが宣蚀された倉数にも圓おはたりたす。



この状況を回避するには、各関数/倉数を䞀意の名前で呌び出すか、クロヌゞャヌを䜿甚する必芁がありたす。 各関数ず倉数を䞀意の名前で倉圢しお名前を付けるのは䞍䟿であり、完党な䞀意性を保蚌するものではありたせん。 䞀方、クロヌゞャヌメカニズムは、倉数ず関数の呜名に完党な自由を提䟛したす。 これを行うには、宣蚀の盎埌に実行される匿名関数でコヌド党䜓をラップするだけで十分です。



 (function(){ /*  ,     */ })();
      
      







その結果、宣蚀されたすべおの倉数ず関数はグロヌバルスコヌプで䜿甚できなくなりたす。぀たり、競合は発生したせん。



それでも1぀たたは2぀の機胜にグロヌバルにアクセスできるこずが必芁な堎合はどうすればよいですか そしお、ここではすべおがずおも簡単です。 グロヌバルスコヌプを提䟛する最もグロヌバルなオブゞェクトは、 りィンドりオブゞェクトです。 関数はオブゞェクトであるずいう事実により、関数をりィンドりプロパティに割り圓おお、グロヌバルになるこずができたす。 プラむベヌトスコヌプからグロヌバル関数を宣蚀する䟋



 (function(){ var title = "Hello World"; function showTitle(){ alert(title); } window.showSimpleTitle = showTitle; })(); showSimpleTitle();
      
      







コヌド実行の結果、メッセヌゞ「 Hello World 」が生成されたす-ロヌカルのshowTitle関数は showSimpleTitleずいう名前でグロヌバルに䜿甚可胜になり、匿名関数の倖郚ではアクセスできない「closed」倉数titleを䜿甚したす。



なぜなら すぐに実行される匿名関数ですべおをラップするず、この関数にパラメヌタヌを枡すこずができたす。この関数内では、ロヌカル名で䜿甚できたす。 JQueryの䟋



 (function(){ $('.hidden').hide(); })();
      
      







グロヌバル倉数$がjQueryでない堎合、゚ラヌがスロヌされたす。 これは、jQueryに加えお、$関数を䜿甚する別のラむブラリPrototype.JSなどが䜿甚されおいる堎合に発生したす。 「額」の解決策



 (function(){ var $ = jQuery; $('.hidden').hide(); })();
      
      







動䜜し、正しく動䜜したす。 しかし、あたりきれいではありたせん。 よりきれいな解決策がありたす-ロヌカル倉数$を関数ぞの匕数ずしお宣蚀し、そこにjQueryオブゞェクトを枡したす



 (function($){ /* ,  $ */ })(jQuery);
      
      







関数のすべおの匕数がデフォルトでロヌカル倉数であるこずを思い出すず、匿名関数$の内郚ではjQueryオブゞェクトぞの参照であるグロヌバルオブゞェクト$に接続されおいないこずが明らかになりたす。 匿名関数による受信をより理解しやすくするために、匿名関数を非匿名にするこずができたす-関数を宣蚀しおすぐに起動したす



 function __run($){ /* code */ } __run(jQuery);
      
      







それでも、グロヌバル関数$を呌び出す必芁がある堎合は、 windowを䜿甚できたす。



2぀目は、クロヌゞャヌを䜿甚した関数の動的な宣蚀です。



むベントモデルを䜿甚する堎合、同じむベントを異なる芁玠でハングアップする必芁がある堎合によく発生したす。 たずえば、10個のdiv芁玠があり、クリックするずalertNを呌び出す必芁がありたす Nは䞀意の芁玠番号です。



クロヌゞャヌを䜿甚した最も簡単な゜リュヌション



 for(var counter=1; counter <=10; counter++){ $('<div>').css({ "border": "solid 1px blue", "height": "50px", "margin": "10px", "text-align": "center", "width": "100px" }).html('<h1>'+ counter +'</h1>') .appendTo('body') .click(function(){ alert(counter); }); }
      
      







ただし、このコヌドを実行するず「予期しない」結果が発生したす。すべおのクリックで同じ数が衚瀺されたす-11。



答えは簡単です。 カりンタヌ倉数の倀は、芁玠をクリックしたずきに取埗されたす。 そしお、その時たでに倉数の倀は11サむクルを終了するための条件になっおいたため、それに応じおすべおの芁玠に察しお11が衚瀺されたす。



正しい解決策は、芁玠ごずに個別にクリック凊理関数を動的に生成するこずです。



 for(var counter=1; counter <=10; counter ++){ $('<div>').css({ "border": "solid 1px blue", "height": "50px", "margin": "10px", "text-align": "center", "width": "100px" }).html('<h1>'+ counter +'</h1>') .appendTo('body') .click((function(iCounter){ return function(){ alert(iCounter); } })(counter)); }
      
      







このアプロヌチでは、 カりンタヌをパラメヌタヌずしお受け取り、動的関数を返す匿名関数を䜿甚したす。 匿名関数内では、 ロヌカル倉数iCounterには、関数が呌び出されたずきの珟圚のカりンタヌ倀が含たれおいたす。 たた、関数を呌び出すたびにすべおのロヌカル倉数が再宣蚀されるため新しいクロヌゞャヌが䜜成されるため、匿名関数が呌び出されるず、新しい「ダむナミック関数」が、既に「閉じた」番号ずずもに返されたす。



簡単に蚀うず、関数を2回3回目、4回目...実行するず、すべおのロヌカル倉数がメモリ内に再䜜成され、前の関数呌び出し䞭に䜜成された倉数ずは䜕の関係もありたせん。



難しいですか 初めおだず思う-はい。 しかし、グロヌバル倉数をたくさん持぀必芁はなく、「どこから私を呌び出したのか」ずいう関数でチェックを行いたす。 そしお、デフォルトで枡された関数を呌び出すjQuery.eachを䜿甚するず、コヌドはさらにシンプルで読みやすくなりたす。



 $('div.handle-click').each(function(counter){ $(this).click(function(){ alert(counter); }); });
      
      







クロヌゞャヌのおかげで、矎しく簡朔で理解しやすいコヌドを蚘述し、必芁に応じお倉数ず関数に名前を付けるこずができたす。 たた、このコヌドが他のプラグ可胜なスクリプトず競合しないこずを確認しおください。



非衚瀺のテキスト
倉数クロヌゞャのメカニズムは、内郚関数プロパティ[[Scope]]を䜿甚しお実装されたす-このオブゞェクトは、関数の宣蚀䞭に開始され、芪関数で宣蚀された倉数ぞの参照を含みたす。 このため、䜜業呌び出し䞭に、すべおの「芪」倉数が関数で䜿甚可胜になりたす。 実際、オブゞェクト[[Scope]]はクロヌゞャヌメカニズムのキヌです。



閉鎖メカニズムの詳现に぀いおは、トピックの䞋のリンクにある蚘事をご芧ください。




プロトタむピングたたは「クラスオブゞェクトを䜜成したい」



JavaScriptのプロトタむピングに぀いお曞かれた倚くの優れた蚘事がありたす。 したがっお、私はすでに曞かれおいるこずを繰り返さないようにしたすが、プロトタむプのメカニズムの基瀎を単に説明したす。



JavaScriptにはオブゞェクトの抂念がありたすが、クラスの抂念はありたせん。 タむピングが匱いため、すべおのJavaScriptはオブゞェクトベヌスであるため、JavaScriptのほずんどすべおのデヌタはオブゞェクトであるか、オブゞェクトずしお䜿甚できたす。 たた、クラスの代替ずしお、プロトタむピングの可胜性がありたす-デフォルトでプロパティずメ゜ッドを持぀プロトタむプをオブゞェクトに割り圓おるこずができたす。



JavaScriptでのオブゞェクトの操䜜は非垞に簡単です。オブゞェクトを宣蚀し、プロパティずメ゜ッドを割り圓おるだけです。



 var dog = { "name": "Rocky", "age": "5", "talk": function(){ alert('Name: ' + this.name + ', Age: ' + this.age); } };
      
      







オブゞェクトが倚数ある堎合は、オブゞェクトを返す別の関数を䜜成する方が䟿利です。



 function getDog(name, age){ return { "name": name, "age": age, "talk": function(){ alert('Name: ' + this.name + ', Age: ' + this.age); } }; } var rocky = getDog('Rocky', 5); var jerry = getDog('Jerry', 3);
      
      







プロトタむプを䜿甚しおも同じこずができたす。



 function Dog(name, age){ this['name'] = name; this.age = age; } Dog.prototype = { "talk": function(){ alert('Name: ' + this.name + ', Age: ' + this.age); } }; var rocky = new Dog('Rocky', 5); var jerry = new Dog('Jerry', 3);
      
      







前述のように、プロトタむプはデフォルトのプロパティずメ゜ッドを含む単玔なオブゞェクトです。 ぀たり オブゞェクトでプロパティを取埗しようずするか、オブゞェクトが持たない関数を呌び出すず、JavaScriptむンタヌプリタヌぱラヌを生成する前に、プロトタむプオブゞェクトでこのプロパティ/関数を芋぀けようずしたす。芋぀かった堎合は、プロパティ/関数プロトタむプ。



非衚瀺のテキスト
プロトタむプのプロパティは、読み取り/実行にのみ䜿甚されるこずに泚意しおください。 元のプロパティがオブゞェクト自䜓で芋぀からない堎合、倀ぞのアクセス/関数の実行を詊行する堎合にのみ、それらぞのアクセスが発生したす。



オブゞェクトに䜕らかのプロパティプロトタむプでは利甚可胜ですが、オブゞェクトでは利甚䞍可を割り圓おようずするず、プロパティはオブゞェクトで正確に䜜成され、プロトタむプでは倉曎されたせん。




JavaScriptは非垞に柔軟な蚀語です。 したがっお、抂しお、プロトタむプを䜿甚しお実行できるこずはすべお、プロトタむプなしで実行できたす。 ただし、プロトタむプを䜿甚するず、倉曎ず継承、およびOOPに近い構文により柔軟な可胜性が提䟛されたす。 興味のある方のために、蚘事の最埌に、独自のクラスを実装するためのメカニズムず可胜性の詳现な説明を含む蚘事ぞのリンクがありたす。



そしお、プロトタむプを䜿甚しお既存のオブゞェクトの機胜を拡匵する小さな説明的な䟋


任意の日付から曜日の名前を取埗する必芁がありたすが、組み蟌みのDateオブゞェクトにはgetDayメ゜ッドのみが含たれおおり、曜日の数倀衚珟を0〜6で返したす日曜日から土曜日。



これを行うこずができたす



 function getDayName(date){ var days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']; return days[date.getDay()]; } var today = new Date(); alert(getDayName(today));
      
      







たたは、プロトタむピングを䜿甚しお、組み蟌みの日付オブゞェクトを拡匵したす。



 Date.prototype.getDayName = function(){ var days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']; return days[this.getDay()]; } var today = new Date(); alert(today.getDayName());
      
      







2番目の方法はより゚レガントで、「䜙分な」関数でスコヌプを詰たらせるこずはないず思いたす。䞀方、耇数の人がコヌドに取り組んでいる堎合、埋め蟌みオブゞェクトの拡匵は悪い圢であるずいう意芋がありたす。したがっお、これには泚意する必芁がありたす。



実行コンテキストたたは「This Mysterious this」



OOPが䜿甚されおいる他のプログラミング蚀語からJavaScriptに切り替えるず、このオブゞェクトがJavaScriptで䜕を意味するかを理解するこずは非垞に困難です。簡単に説明しようずするず、これは関数が呌び出されるオブゞェクトぞの参照です。䟋



 var exampleObject = { "title": "Example Title", "showTitle": function(){ alert(this.title); } }; exampleObject.showTitle();
      
      







䟋からわかるように、exampleObject.showTitleを呌び出すず、関数はオブゞェクトメ゜ッドずしお呌び出され、この関数内で関数を呌び出したexampleObjectオブゞェクトを参照したす。関数自䜓はオブゞェクトには䞀切付加されず、個別に存圚したす。コンテキストバむンディングは、関数呌び出し䞭に盎接発生したす。



 function showTitle(){ alert(this.title); } var objectA = { "title": "Title A", "showTitle": showTitle }; var objectB = { "title": "Title B", "showTitle": showTitle }; objectA.showTitle(); objectB.showTitle();
      
      







この䟋で明らかにコヌルするこずを瀺しおいるobjectA.showTitleは 、これはを参照ObjectAに、ず呌び出しobjectB.showTitleを - ObjectBに䞊。showTitle関数自䜓は別個に存圚し、䜜成時にプロパティずしおオブゞェクトに単玔に割り圓おられたす。



関数を呌び出すずきに、関数関数がオブゞェクトを参照しない堎合、関数内のこれはグロヌバルりィンドりオブゞェクトを参照したす。぀たり単にshowTitleを呌び出すず、タむトル倉数が宣蚀されおいないずいう゚ラヌが生成されたす。ただし、グロヌバル倉数titleを宣蚀するず、関数はこの倉数の倀を出力したす。



 var title = "Global Title"; function showTitle(){ alert(this.title); } showTitle();
      
      







非衚瀺のテキスト
Strict Mode : , this window , this .




関数のコンテキストが呌び出し䞭に正確に決定されるこずを瀺すために、関数がオブゞェクトメ゜ッドずしおのみ最初に存圚する䟋を瀺したす。



 var title = "Global Title"; var exampleObject = { "title": "Example Title", "showTitle": function(){ alert(this.title); } }; var showTitle = exampleObject.showTitle; //      showTitle(); //        
      
      







実行の結果、メッセヌゞ「Global Title」が衚瀺されたす。これは、関数呌び出し䞭に、これがexampleObjectオブゞェクトではなくグロヌバルりィンドりオブゞェクトを指すこずを意味したす。これは、var行のshowTitle = exampleObject.showTitleで関数ぞのリンクのみを取埗し、showTitleが呌び出されるず、この参照をりィンドりオブゞェクトにする元のexampleObjectぞの参照がないためです。簡単にするために、関数がオブゞェクトのプロパティずしお呌び出される堎合、これはこのオブゞェクトを参照したす。発信者がいない堎合、これ



グロヌバルりィンドりオブゞェクトを参照したす。



よくある間違いの䟋



 var exampleObject = { "title": "Example Title", "showTitle": function(){ alert(this.title); } }; jQuery('#exampleDiv').click(exampleObject.showTitle);
      
      







予想される「Example Title」ではなくID「exampleDiv」のDIVをクリックするず、空の行たたはDIVの「title」属性の倀が衚瀺されたす。これは、クリックむベントに関数を䞎えるが、オブゞェクトには䞎えないずいう事実によるものです。そしお、その結果、元のexampleObjectを参照せずに関数が起動されたす䟿宜䞊、jQueryは芁玠自䜓のコンテキストでハンドラヌ関数を実行し、同様の結果に぀ながりたす。オブゞェクトにバむンドされた関数を開始するには、オブゞェクトぞの参照を䜿甚しお関数を呌び出す必芁がありたす。



 jQuery('#exampleDiv').click(function(){ exampleObject.showTitle(); });
      
      







JavaScript自䜓を䜿甚しお、このような「䞍噚甚な」宣蚀を回避するには、bindを䜿甚しお関数をコンテキストにバむンドできたす。



 jQuery('#exampleDiv').click(exampleObject.showTitle.bind(exampleObject));
      
      







ただし、バヌゞョン9以前の誰もが愛する IEはこの機胜をサポヌトしおいたせん。したがっお、ほずんどのJSラむブラリは、この機胜を䜕らかの圢で独立しお実装したす。たずえば、jQueryではプロキシです。



 jQuery('#exampleDiv').click(jQuery.proxy(exampleObject.showTitle, exampleObject)); //  : jQuery('#exampleDiv').click(jQuery.proxy(exampleObject, "showTitle"));
      
      







このアプロヌチの本質は非垞に単玔です。jQuery.proxyが呌び出されるず、匿名関数が返され、クロヌゞャヌを䜿甚しお、枡されたオブゞェクトのコンテキストで元の関数が呌び出されたす。



実際、JavaScriptは任意のコンテキストで任意の関数を実行できたす。たた、オブゞェクトに機胜を割り圓おる必芁もありたせん。JavaScriptでこれを行うには、適甚ず呌び出しの 2぀の方法がありたす。



 function showTitle(){ alert(this.title); } var objectA = { "title": "Title A", }; var objectB = { "title": "Title B", }; showTitle.apply(objectA); showTitle.call(objectA);
      
      







関数のパラメヌタヌを䜿甚しなくおも、䞡方ずも同じように機胜したす。適甚関数ず呌び出し関数は、呌び出されたずきにパラメヌタヌが枡される方法のみが異なりたす。



 function example(A, B, C){ /* code */ } example.apply(context, [A, B, C]); example.call(context, A, B, C);
      
      







取り䞊げられおいるトピックの詳现に぀いおは、次を参照しおください。




All Articles