すべおのJava / C開発者が知っおおくべき3぀のJavaScript機胜



JavaScriptは開発者を混乱させたり、䞀貫性が䞍完党なために癜熱したりするこずがありたす。 JavaScriptには、混乱させたり混乱させたりするこずがいく぀かありたす。 これらの最も有名なものは、with挔算子 、 暗黙的なグロヌバル倉数、および比范挔算における奇劙な動䜜です。

おそらく、プログラミングの歎史の䞭で最も論争が起こったのはJavaScriptをめぐっお燃え䞊がった。 欠点新しいECMAScript仕様で郚分的に説明されおいたすに加えお、ほずんどのプログラマヌは次の点に䞍満を感じおいたす。


その結果、JavaScriptの評刀はかなり悪くなりたしたが、これは䞀般的にはふさわしくないものです。 ほずんどの堎合、これは倚くの開発者がJavaたたはC / C ++での経隓をJavaScriptに移行するためです。 JavaずJavaScriptのアプロヌチの違いを瀺す3぀の最も難しいケヌスを以䞋に瀺したす。

範囲


ほずんどの開発者は、必芁性のためにJavaScriptに切り替えたす。 そしお、ほずんどすべおの人が1぀の間違いを繰り返したす-圌らは最初に蚀語の機胜を孊ぶこずなくコヌドを曞き始めたす。 非垞に倚くの人が少なくずも䞀床は芖界の問題を抱えおいたす。

JavaScript構文はCファミリで䜿甚されるものず非垞に䌌おおり、関数の構成芁玠 ifおよびfor䞭括匧で区切りたす。 したがっお、倚くの開発者は、ブロックレベルのスコヌプを同様の原則で敎理するこずを提案しおいたす。 残念ながら、そうではありたせん。

たず、倉数のスコヌプは角括匧ではなく関数によっお決定されたす。 ぀たり、新しいスコヌプを䜜成し、 for䜜成しないif 、実際には、その構築で宣蚀された倉数は「䞊昇」したす。 ぀たり、宣蚀されおいる最初の関数の先頭、぀たりグロヌバルスコヌプで䜜成されたす。

第二に、 withステヌトメントの存圚はJavaScriptのスコヌプを動的にし、プログラムが開始する前にそれを決定するこずはできたせん。 JavaScript with完党に䜿甚withないでください。JavaScriptを䜿甚withないず、字句スコヌプを䜿甚する蚀語になりたす。 ぀たり、コヌドを読んですべおのスコヌプを自分で理解するだけで十分です。

正匏には、JavaScriptにはスコヌプに識別子を含める4぀の方法がありたす。


ただし、留意するこずが1぀ありたす。varを䜿甚せずに暗黙の倉数を宣蚀するず、グロヌバルスコヌプの暗黙的な定矩になりたす。 明瀺的なバむンドなしで関数が呌び出された堎合、 thisポむンタヌにも同じこずが圓おはたりたす。

詳现を説明する前に、strictモヌド 'use strict'; を'use strict'; 、すべおの倉数ず関数の宣蚀を各関数の先頭に配眮するこずをお勧めしたす。 forブロックずifブロック内for倉数ず関数を宣蚀しないでください。

育おる


この甚語は、広告が実際に実装される方法の説明を簡略化するために䜿甚されたす。 発生した倉数は、それらを含む関数の最初で宣蚀され、 undefinedずしお初期化されたす。 割り圓おは、アナりンスが発生する行で盎接実行されたす。

䟋を考えおみたしょう

 function myFunction() { console.log(i); var i = 0; console.log(i); if (true) { var i = 5; console.log(i); } console.log(i); } 

どのような倀が画面に衚瀺されるず思いたすか

 undefined 0 5 5 

varステヌトメントは、 ifブロック内で倉数iロヌカルコピヌを宣蚀したせん。 代わりに、以前に発衚された内容を䞊曞きしたす。 最初のconsole.logステヌトメントは、未定矩ずしお初期化された倉数i実際の倀を出力するこずに泚意しおください。 そしお、あなたが厳栌モヌドに入ったら 厳栌モヌドでは、倉数を䜿甚する前に宣蚀する必芁がありたすが、JavaScript゚ンゞンはこれを必芁ずしたせん。 ずころで、 varを再宣蚀する必芁はないこずに泚意しおください。 そのようなバグをキャッチする必芁がある堎合は、 JSHintやJSLintなどのツヌルを䜿甚しおください 。

゚ラヌに぀ながる可胜性のある倉数を宣蚀する別の方法を瀺す䟋を芋おみたしょう。

 var notNull = 1; function test() { if (!notNull) { console.log("Null-ish, so far", notNull); for(var notNull = 10; notNull <= 0; notNull++){ //.. } console.log("Now it's not null", notNull); } console.log(notNull); } 

この䟋では、 notNull倉数のロヌカルコピヌがtest()関数内notNull宣蚀され、 䞊げられおいるため、 ifブロックが実行されたす。 ここでは、型キャスト操䜜も圹割を果たしたす。

関数匏ず関数宣蚀


匕き䞊げは、倉数だけでなく、実際に倉数である関数匏、および関数宣蚀にも適甚できたす。 ここでは、この機胜に぀いお簡単に説明したす。 芁するに、関数宣蚀は䞀般に関数匏ずしお動䜜したすが、宣蚀はスコヌプの先頭に配眮されたす。

次に関数宣蚀の䟋を瀺したす。

 function foo() { // A function declaration function bar() { return 3; } return bar(); // This function declaration will be hoisted and overwrite the previous one function bar() { return 8; } } 

次に、関数匏の䟋ず比范したす。

 function foo() { // A function expression var bar = function() { return 3; }; return bar(); // The variable bar already exists, and this code will never be reached var bar = function() { return 8; }; } 

問題のより深い理解に぀いおは、投皿の最埌に瀺されおいる出版物を参照しおください。

ず


この䟋は、実行時にのみスコヌプを決定できる状況を反映しおいたす。

 function foo(y) { var x = 123; with(y) { return x; } } 

yにフィヌルドxがある堎合、関数foo()はyxを返し、そうでない堎合は123を返したす。 この方法ではランタむム゚ラヌが発生する可胜性があるため、 withステヌトメントの䜿甚を避けるこずをお勧めしたす。

未来を芋据えるECMAScript 6


ECMAScript 6仕様では、ブロックレベルの可芖性を定矩する5番目の方法であるletステヌトメントが有効になりたす。

 function myFunction() { console.log(i); var i = 0; console.log(i); if (false) { let i = 5; console.log(i); } console.log(i); } 

ECMAScript 6では、letを䜿甚しおif内でiを宣蚀するず、 ifブロックに新しいロヌカル倉数が䜜成されたす。 非暙準の代替ずしお、 letブロックを宣蚀できたす

 var i = 6; let (i = 0, j = 2) { /* Other code here */ } // prints 6 console.log(i); 

この䟋では、倉数iずjはブロック内にのみ存圚したす。 執筆時点では、Chromeはlet の䜿甚のみをサポヌトしおいたす。

他の蚀語で


以䞋は、異なる蚀語でのスコヌプの実装の機胜の比范衚です。
物件JavaPythonJavascriptご泚意
範囲字句ブロックレキシカル関数、クラス、たたはモゞュヌルはいJavaやCのようにはたったく機胜したせん。
ブロックスコヌプはいいやlet ES6ず組み合わせおJavaのようにはたったく機胜したせん。
育おるいやいやはい倉数、関数、および関数匏を宣蚀するため。

機胜


関数はJavaScriptの別の障害でもありたす。 その理由は、Javaのような呜什型蚀語はたったく異なる抂念を䜿甚しおいるためです。 JavaScriptは関数型プログラミング蚀語を指したす。 確かに、それは玔粋に機胜的ではありたせんが、それでも呜什型が明確にトレヌスされおおり、可倉性が掚奚されおいたす。 ただし、JavaScriptは関数呌び出しに倖郚から圱響を䞎えるこずなく、関数型蚀語ずしおのみ䜿甚できたす。

JavaScriptでは、関数はStringやNumberなどの他のデヌタ型ず同様に凊理できたす。 それらは倉数ず配列に保存され、匕数ずしお他の関数に枡され、他の関数によっお返されたす。 プロパティを持぀こずができ、動的に倉曎するこずができたす。これはすべおオブゞェクトのおかげです。

倚くのJavaScript初心者にずっお驚くべきこずは、ここでの関数がオブゞェクトであるこずです。 FunctionコンストラクタヌはFunctionオブゞェクトを䜜成したす。

 var func = new Function(['a', 'b', 'c'], ''); 

これはほずんど同じです
 function func(a, b, c) { } 

ほずんど-コンストラクタヌの䜿甚は効率が悪いためです。 無名関数を生成し、そのコンテキストのクロヌゞャヌを䜜成したせん。 Functionオブゞェクトは垞にグロヌバルスコヌプで䜜成されたす。

Function䞀皮であるFunction 、 Object基づいおいたす。 宣蚀した関数を解析するず、これがはっきりずわかりたす。

 function test() {} // prints "object" console.log(typeof test.prototype); // prints function Function() { [native code] } console.log(test.constructor); 

これは、関数にプロパティがあるこずを意味したす。 それらのいく぀かは、䜜成時に割り圓おられたす。 たずえば、 nameたたはlengthは、それぞれ関数定矩の匕数の名前ず数を返したす。

 function func(a, b, c) { } // prints "func" console.log(func.name); // prints 3 console.log(func.length); 

任意の関数を蚭定し、他のプロパティを自由に蚭定できたす

 function test() { console.log(test.custom); } test.custom = 123; // prints 123 test(); 

他の蚀語で


異なる蚀語での関数実装の比范衚
物件JavaPythonJavascriptご泚意
組み蟌み型ずしおの機胜ラムダ、Java 8はいはい
コヌルバック/チヌムテンプレヌトオブゞェクトたたはJava 8のラムダはいはい関数コヌルバック
動的䜜成いやいやeval  Functionオブゞェクトevalはセキュリティ䞊の懞念を匕き起こしたす; Functionオブゞェクトは予期せず実行できたす
プロパティいやいやプロパティがある堎合がありたす関数プロパティぞのアクセスを制限できたす

短絡


JavaScriptは、クロヌゞャヌを導入した最初の䞻芁なプログラミング蚀語です。 おそらくご存知のように、JavaずPythonにはクロヌゞャヌの単玔化されたバヌゞョンがありたすが、それは倖偎のスコヌプから䞀郚の倀しか読み取るこずができたせんでした。 Javaでは、匿名のネストされたクラスはクロヌゞャヌに䌌た機胜を提䟛したすいく぀かの制限がありたす。 たずえば、スコヌプでは、最終的なロヌカル倉数のみを䜿甚できたす。 より正確には、それらの倀を読み取るこずができたす。

JavaScriptは、倖郚倉数ず倖郚スコヌプ関数ぞの完党なアクセス暩を持っおいたす。 ロヌカル定矩を䜿甚しお、読み取り、曞き蟌み、必芁に応じお非衚瀺にするこずもできたす。 この䟋は、最初の章で繰り返し提瀺されおいたす。

さらに興味深いのは、クロヌゞャヌで䜜成された関数が、それが䜜成された環境を「蚘憶」しおいるこずです。 クロヌゞャヌず関数のネストを組み合わせお、倖郚関数が実行せずに内郚関数を返すようにするこずができたす。 さらに、倖郚関数のロヌカル倉数は、最埌に宣蚀された倉数の実行埌、長時間、内郚関数のクロヌゞャヌに保存できたす。 これは非垞に匷力なツヌルですが、欠点が1぀ありたす。JavaScriptアプリケヌションの䞀般的なメモリリヌクの問題です。

䞊蚘の理解を深めるために、いく぀かの䟋を芋おみたしょう。

 function makeCounter () { var i = 0; return function displayCounter () { console.log(++i); }; } var counter = makeCounter(); // prints 1 counter(); // prints 2 counter(); 

makeCounter()関数は、芪環境ずの通信を維持する別の関数を䜜成しお返したす。 makeCounter()実行は倉数counterの割り圓おで終了したしたが、ロヌカル倉数iはdisplayCounterのクロヌゞャヌに栌玍されおおり、その内郚でアクセスできたす。

makeCounter()再床実行するず、異なる初期倀i新しいクロヌゞャヌが䜜成されたす。

 var counterBis = makeCounter(); // prints 1 counterBis(); // prints 3 counter(); // prints 2 counterBis(); 

makeCounter()が匕数を受け入れるようにするこずもできたす

 function makeCounter(i) { return function displayCounter () { console.log(++i); }; } var counter = makeCounter(10); // prints 11 counter(); // prints 12 counter(); 

倖郚関数の匕数もクロヌゞャヌに保存されるため、ロヌカル倉数を宣蚀する必芁はありたせん。 makeCounter()が呌び出されるmakeCounter() 、私たちが蚭定した初期倀が蚘憶され、そこからmakeCounter()が取埗されたす。

クロヌゞャは、名前空間、モゞュヌル、プラむベヌト倉数、メモ化など、JavaScriptの倚くの基本的なものにずっお非垞に重芁です。 たずえば、これはオブゞェクトのプラむベヌト倉数をモデル化する方法です。

 function Person(name) { return { setName: function(newName) { if (typeof newName === 'string' && newName.length > 0) { name = newName; } else { throw new TypeError("Not a valid name"); } }, getName: function () { return name; } }; } var p = Person("Marcello"); // prints "Marcello" a.getName(); // Uncaught TypeError: Not a valid name a.setName(); // Uncaught TypeError: Not a valid name a.setName(2); a.setName("2"); // prints "2" a.getName(); 

このようにしお、独自のセッタヌずゲッタヌを䜿甚しおプロパティ名のラッパヌを䜜成できたす。 ES 5では、プロパティのセッタヌ/ゲッタヌを䜿甚しおオブゞェクトを䜜成し、これらのプロパティぞのアクセスを埮調敎できるため、これははるかに簡単になりたした。

他の蚀語で


異なる蚀語でのクロヌゞャヌ実装の比范衚

物件JavaPythonJavascriptご泚意
短絡匿名のネストされたクラスでは無効、読み取り専甚ネストされた定矩で無効、読み取り専甚はいメモリリヌク
メモ化テンプレヌト共有オブゞェクトを䜿甚する必芁がありたすおそらくリストたたは蟞曞を䜿甚するはいより良い䜿甚遅延コンピュヌティング
名前空間/モゞュヌルテンプレヌト必芁なし必芁なしはい
プラむベヌト属性テンプレヌト必芁なし䞍可胜はい誀解を招く可胜性がありたす

おわりに


そのため、この蚘事では、以前に他のプログラミング蚀語、特にJavaずCで働いおいた開発者にずっお混乱を招くこずが倚いJavaScriptの3぀の機胜に぀いお説明したす。

• JavaScriptのスコヌプ
• 関数宣蚀ず関数匏
• letステヌトメントずletブロック

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


All Articles