JavaScriptスコヌプに぀いお知りたいこずすべおただし、尋ねるのが怖かった

JSにはスコヌプに関連するいく぀かの抂念がありたすが、初心者の開発者および経隓豊富な開発者でもには必ずしも明確ではありたせん。 この蚘事は、スコヌプ、クロヌゞャ、「this」、ネヌムスペヌス、関数のスコヌプ、グロヌバル倉数、レキシカルスコヌプ、プラむベヌトおよびパブリック゚リアなどの蚀葉を聞いお、JSスコヌプの深intoに飛び蟌もうずする人々に捧げられおいたす。資料を読んで、次の質問に答えるこずができたす。

-スコヌプずは䜕ですか
-グロヌバル/ロヌカルOSずは䜕ですか
-名前空間ずは䜕ですかOBずはどう違いたすか
-このキヌワヌドの意味ず、OBずの関係は
-機胜的および語圙的OBずは䜕ですか
-閉鎖ずは䜕ですか
-このすべおをどのように理解しお䜜成できたすか

スコヌプずは䜕ですか



JSでは、スコヌプはコヌド内の珟圚のコンテキストです。 OBはロヌカルたたはグロヌバルに定矩できたす。 防匟コヌドを曞く鍵は、OBを理解するこずです。 倉数ず関数が利甚できる堎所、コヌド内のコンテキストを倉曎し、より高速でよりサポヌトされたコヌドデバッグが高速を蚘述する方法を理解したしょう。 OMに察凊するのは簡単です。AかBのどちらのOMに今入っおいるのかずいう質問を自問したす。

グロヌバル/ロヌカルOBずは䜕ですか



1行のコヌドを蚘述するこずなく、すでにグロヌバルOBにいたす。 倉数をすぐに定矩する堎合、倉数はグロヌバルOBにありたす。

//   var name = 'Todd'; 


グロヌバルOBはあなたの芪友であり、最悪の悪倢です。 異なる゚ヌゞェントず連携するこずを孊ぶず、名前の共通郚分が衚瀺されない限り、グロヌバル゚ヌゞェントの問題は発生したせん。 倚くの堎合、「グロヌバルOB-これは悪い」ず聞くこずができたすが、その理由の説明はほずんど埗られたせん。 GOV-悪くはありたせん。異なるOBから利甚できるモゞュヌルずAPIを䜜成するずきに䜿甚する必芁がありたす。利益を埗るために慎重に䜿甚する必芁がありたす。

私たちはすべおjQueryを䜿甚したした。 曞いたらすぐに

 jQuery('.myClass'); 


グロヌバルOBでjQueryにアクセスし、このアクセスを名前空間ず呌ぶこずができたす。 甚語「名前空間」は、甚語OBの代わりに䜿甚される堎合がありたすが、通垞はレベル自䜓のOBを瀺したす。 この堎合、jQueryはグロヌバルOBにあり、名前空間です。 jQuery名前空間は、jQueryラむブラリのPIずしお機胜するグロヌバルOBで定矩されたすが、そのすべおのコンテンツはこのPIから継承されたす。

ロヌカルOBずは䜕ですか



ロヌカルOMは、グロヌバルの埌に定矩されたOMず呌ばれたす。 通垞、1぀のGOVがあり、定矩された各関数にはロヌカルOBが含たれたす。 別の関数内で定矩された各関数には、倖郚関数のOBに関連付けられた独自のロヌカルOBがありたす。

関数を定矩しお内郚で倉数を蚭定するず、それらはロヌカルOBに属したす。 䟋

 //  A:  var myFunction = function () { //  B:  }; 


BWTのすべおの倉数はGOWに衚瀺されたせん。 倖郚から盎接アクセスするこずはできたせん。 䟋

 var myFunction = function () { var name = 'Todd'; console.log(name); // Todd }; // ReferenceError: name is not defined console.log(name); 


倉数「name」はロヌカルOBを参照したす。倖郚からは芋えないため、定矩されおいたせん。

機胜的OB。



すべおのロヌカルOBは、機胜OBでのみ䜜成され、forルヌプやwhileルヌプ、たたはifやswitchなどのディレクティブによっおは䜜成されたせん。 新しい機胜は新しいスコヌプです。 䟋

 //  A var myFunction = function () { //  B var myOtherFunction = function () { //  C }; }; 


そのため、新しいOBずロヌカル倉数、関数、オブゞェクトを簡単に䜜成できたす。

レキシカルOB



1぀の関数が別の関数の内郚で定矩されおいる堎合、内郚は倖郚OMにアクセスできたす。 これは、「字句OB」たたは「クロヌゞャ」たたは「静的OB」ず呌ばれたす。

 var myFunction = function () { var name = 'Todd'; var myOtherFunction = function () { console.log('My name is ' + name); }; console.log(name); myOtherFunction(); //   }; // : // `Todd` // `My name is Todd` 


レキシカルOBを䜿甚するのは非垞に簡単です。芪のOBで定矩されおいるものはすべお、子のOBで䜿甚できたす。 䟋

 var name = 'Todd'; var scope1 = function () { // name   var scope2 = function () { // name   var scope3 = function () { // name   ! }; }; }; 


逆方向では、これは機胜したせん。

 // name = undefined var scope1 = function () { // name = undefined var scope2 = function () { // name = undefined var scope3 = function () { var name = 'Todd'; //   }; }; }; 


「名前」ぞのリンクはい぀でも返すこずができたすが、倉数自䜓は返せたせん。

OBシヌケンス



OBのシヌケンスは、遞択した機胜のOBを決定したす。 定矩された各関数には独自のOMがあり、別の内郚で定矩された各関数には独自のOMがあり、倖郚OMに接続されおいたす-これはシヌケンスたたはチェヌンです。 コヌド内の䜍眮は、OBを定矩したす。 倉数の倀を決定するず、JSは探しおいる関数、オブゞェクト、たたは倉数が芋぀かるたで、最も深い埋め蟌みOBから倖偎に向かっおいきたす。

短絡



圌らは語圙OBず密接な同盟関係にありたす。 良い䜿甚䟋は、関数参照を返すこずです。 内郚で定矩されたものにアクセスできるようにするさたざたなリンクを匕き出すこずができたす。

 var sayHello = function (name) { var text = 'Hello, ' + name; return function () { console.log(text); }; }; 


テキストを衚瀺するには、sayHello関数を呌び出すだけでは䞍十分です。

 sayHello('Todd'); //  


関数は関数を返すので、最初に関数を割り圓おおから呌び出す必芁がありたす。

 var helloTodd = sayHello('Todd'); helloTodd(); //     'Hello, Todd' 


もちろん、盎接クロヌゞャを匕き起こすこずができたす

 sayHello('Bob')(); //     


AngularJSは、$ compileメ゜ッドで同様の呌び出しを䜿甚したす。この堎合、珟圚のOBぞのリンクを枡す必芁がありたす。

 $compile(template)(scope); 


簡単に蚀うず、コヌドは次のようになっおいるず掚枬できたす。

 var $compile = function (template) { //   //    scope return function (scope) { //      `template`   `scope` }; }; 


関数は、クロヌゞャヌになるために䜕も返す必芁はありたせん。 珟圚のOBの倖郚から倉数にアクセスするず、クロヌゞャヌが䜜成されたす。

OVず「これ」



各OBは、関数の呌び出し方法に応じお、「this」倉数に倀を割り圓おたす。 私たちはすべおthisキヌワヌドを䜿甚したしたが、それがどのように機胜し、呌び出しの違いが䜕であるかを党員が理解しおいるわけではありたせん。 デフォルトでは、最も倖偎のOBのオブゞェクトである珟圚のりィンドりを参照したす。 さたざたな呌び出しがこの倀をどのように倉曎するかの䟋

 var myFunction = function () { console.log(this); // this = , [ Window] }; myFunction(); var myObject = {}; myObject.myMethod = function () { console.log(this); // this =   { myObject } }; var nav = document.querySelector('.nav'); // <nav class="nav"> var toggleNav = function () { console.log(this); // this =  <nav> }; nav.addEventListener('click', toggleNav, false); 


この倀には問題もありたす。 次の䟋では、同じ関数内で倀ずOBを倉曎できたす。
 var nav = document.querySelector('.nav'); // <nav class="nav"> var toggleNav = function () { console.log(this); // <nav> element setTimeout(function () { console.log(this); // [ Window] }, 1000); }; nav.addEventListener('click', toggleNav, false); 


ここでは、むベントハンドラから呌び出されない新しいOBを䜜成したした。぀たり、りィンドりオブゞェクトを参照したす。 たずえば、混乱しないように、この倀を別の倉数に保存できたす。

 var nav = document.querySelector('.nav'); // <nav class="nav"> var toggleNav = function () { var that = this; console.log(that); //  <nav> setTimeout(function () { console.log(that); //  <nav> }, 1000); }; nav.addEventListener('click', toggleNav, false); 


.call、. apply、および.bindを䜿甚しおOBを倉曎したす



必芁に応じおOSを倉曎する必芁がある堎合がありたす。
䟋では

 var links = document.querySelectorAll('nav li'); for (var i = 0; i < links.length; i++) { console.log(this); // [ Window] } 


この倀は反埩芁玠には適甚されず、䜕も呌び出したり、OBを倉曎したりしたせん。 OBを倉曎する方法を芋おみたしょうより正確には、関数呌び出しのコンテキストを倉曎したす。

.callおよび.apply



.callおよび.applyメ゜ッドにより、OBを関数に枡すこずができたす。

 var links = document.querySelectorAll('nav li'); for (var i = 0; i < links.length; i++) { (function () { console.log(this); }).call(links[i]); } 


その結果、反埩された芁玠の倀がこれに枡されたす。 .callメ゜ッドscope、arg1、arg2、arg3はコンマで区切られた匕数のリストを受け取り、.applyscope、[arg1、arg2]メ゜ッドは匕数の配列を受け取りたす。

.callたたは.applyメ゜ッドは関数を呌び出すこずを芚えおおくこずが重芁です。

 myFunction(); //  myFunction 


let .call関数を呌び出しおパラメヌタヌを枡したす。

 myFunction.call(scope); 


.bind



.bindは関数を呌び出したせんが、呌び出す前に倉数の倀を単にバむンドしたす。 ご存じのずおり、関数参照にパラメヌタヌを枡すこずはできたせん。

 //  nav.addEventListener('click', toggleNav, false); //      nav.addEventListener('click', toggleNav(arg1, arg2), false); 


これは、新しいネストされた関数を䜜成するこずで修正できたす。

 nav.addEventListener('click', function () { toggleNav(arg1, arg2); }, false); 


しかし、ここでもOMに倉曎があり、远加の関数が䜜成され、パフォヌマンスに悪圱響を及がしたす。 したがっお、.bindを䜿甚したす。その結果、匕数を枡しお関数が呌び出されないようにするこずができたす。

 nav.addEventListener('click', toggleNav.bind(scope, arg1, arg2), false); 

プラむベヌトおよびパブリック゚ヌゞェント



JavaScriptでは、他の倚くの蚀語ずは異なり、パブリックおよびプラむベヌトOSの抂念はありたせんが、クロヌゞャヌを䜿甚しおそれらを゚ミュレヌトできたす。 プラむベヌトOBを䜜成するには、他の関数で関数をラップしたす。

 (function () { //    })(); 


機胜を远加したす。

 (function () { var myFunction = function () { //  ,   }; })(); 


ただし、この関数を盎接呌び出すこずはできたせん。

 (function () { var myFunction = function () { //  ,   }; })(); myFunction(); // Uncaught ReferenceError: myFunction is not defined 


ここにプラむベヌトOBがありたす。 パブリックOVが必芁な堎合は、次のトリックを䜿甚したす。 このモゞュヌルに関連するすべおを含むモゞュヌル名前空間を䜜成したす。

 //   var Module = (function () { return { myMethod: function () { console.log('myMethod has been called.'); } }; })(); //    Module.myMethod(); 


returnディレクティブは、グロヌバルOBで公開されおいるメ゜ッドを返したす。 さらに、これらは目的のネヌムスペヌスに関連しおいたす。 モゞュヌルには、必芁な数のメ゜ッドを含めるこずができたす。

 //   var Module = (function () { return { myMethod: function () { }, someOtherMethod: function () { } }; })(); //    Module.myMethod(); Module.someOtherMethod(); 


グロヌバルOMのすべおのメ゜ッドをダンプしお汚染する必芁はありたせん。 これは、関数を返さずにプラむベヌトOBを線成する方法です。

 var Module = (function () { var privateMethod = function () { }; return { publicMethod: function () { } }; })(); 


publicMethodを呌び出すこずはできたすが、privateMethodを実行するこずはできたせん-プラむベヌトOBを参照したす。 これらの関数には、addClass、removeClass、Ajax / XHR呌び出し、配列、オブゞェクトなど、奜きなものを䜕でも入れるこずができたす。

興味深いひねりは、1぀のOB内ですべおの関数が他のOBにアクセスできるため、パブリックメ゜ッドからグロヌバルOBで䜿甚できないプラむベヌトメ゜ッドを呌び出すこずができるこずです。

 var Module = (function () { var privateMethod = function () { }; return { publicMethod: function () { //     `privateMethod`: // privateMethod(); } }; })(); 


これにより、コヌドの察話性ずセキュリティが向䞊したす。 安党のために、すべおの関数をグロヌバルOBにダンプする䟡倀はないため、呌び出す必芁のない関数が誀っお呌び出されるこずはありたせん。

プラむベヌトメ゜ッドずパブリックメ゜ッドを䜿甚しおオブゞェクトを返す䟋

 var Module = (function () { var myModule = {}; var privateMethod = function () { }; myModule.publicMethod = function () { }; myModule.anotherPublicMethod = function () { }; return myModule; // returns the Object with public methods })(); //  Module.publicMethod(); 


パブリックメ゜ッドずパブリックメ゜ッドを芖芚的に区別するために、プラむベヌトメ゜ッドの名前に䞋線を付けるず䟿利です。

 var Module = (function () { var _privateMethod = function () { }; var publicMethod = function () { }; })(); 


リスト内のメ゜ッドを返し、関数ぞのリンクを返すこずも䟿利です。

 var Module = (function () { var _privateMethod = function () { }; var publicMethod = function () { }; return { publicMethod: publicMethod, anotherPublicMethod: anotherPublicMethod } })(); 

Source: https://habr.com/ru/post/J239863/


All Articles