ダミー用のJavaScript。 あなたが機能について知りたいが、尋ねることを恐れていたすべて

どういうわけか自分自身に気づかないうちに、私はクラスやパターンに煩わされることから離れ、最も一般的なJs関数を扱うことにしました。 私はそれが十分に退屈だと思ったが、私は間違いを犯した-それは非常に興味深いことが判明した。



この記事では、関数の宣言の機能、およびいくつかの有用なパターンについて説明します(そう、そう、それらもここにあります)





1.関数宣言



あらゆる種類の歪みに注意を払わない場合は、次の2つの方法で関数を宣言できます。



//   function a() { console.log(1); } //  ,      b = function() { console.log(2); }
      
      





それらの違いは小さいように見えますが、それはただのようです。



このコードが実行されるとどうなりますか?


 console.log( "sample b" ); b(); function b() { console.log(1); }
      
      





右-すべての名前付き関数がスコープの先頭に転送され、いつでも呼び出すことができるため、例の名前のテキストが最初にコンソールに表示され、次に1つ表示されます。



タスクを複雑にします


 console.log( "sample c" ); function c() { console.log(1); } c(); function c() { console.log(2); }
      
      





しかし、混乱するのはそれほど簡単ではありません。 関数は、作成された順に正確に先頭に転送されます。つまり、コンソールには2つあります。



いいでしょう


 console.log( "sample d" ); d(); var d = function() { console.log(2); }
      
      







回答:ここでルールは異なります-呼び出し時の変数の値が未定義であるため、これはまったく機能しません。



もしそうなら?


 console.log( "sample e" ); var e = function(){ console.log(1); } e(); e = function() { console.log(2); }
      
      





さて、ここではすべてがすでに明確になっています、はい-呼び出しの時点で、 eには最初の関数が含まれているため、コンソールに1つあります。

そして今、最も難しい質問*ドラムロール*の時間です



ここに何がありますか?


 console.log( "sample f" ); var f = function() { console.log(1); } f(); function f(){ console.log(2); } f();
      
      





正解:2回1回。 宣言後、変数は関数にオーバーラップします。

常に。



即時機能



この名前の背後には「ワンタイム」関数があります。名前はなく、アナウンスの直後に実行されます。



なぜこれが必要なのですか? ほとんどの場合、グローバル名前空間を詰まらせることはありません。 たとえば、何かを初期化する必要がある場合、および初期化中に、完全に不要な変数がいくつか必要になります。



このような関数は、本質的に同等の2つの方法で宣言できます。



 console.log("//immidiate function"); //sample a (function(){ console.log( "a" ); })(); //sample b (function(){ console.log( "b" ); }());
      
      





それらの間に違いはありません。



初期化時間分岐



関数の値は、初期化後に変更されない値に依存する場合があります。 まあこのようなもの:



 //   function saySomethingClever(){ var appleTest = /Apple/i; var googleTest = /Google/i; if( appleTest.test(navigator.vendor) ) console.log("I love apples <3") else if( googleTest.test(navigator.vendor) ) console.log("android is everything for me <3") else console.log("i love this unpopular corporation too") } saySomethingClever();
      
      





私たちが電話をかけるたびに、絶対に不要になったチェックを行うことを除いて、すべてが素晴らしいです。 次のように関数を書き換えることができます。



 //   var saySomethingClever = (function(){ var appleTest = /Apple/i; var googleTest = /Google/i; if( appleTest.test(navigator.vendor) ) return function(){ console.log("I love apples <3"); } if( googleTest.test(navigator.vendor) ) return function(){ console.log("android is everything for me <3"); } return function(){ console.log("i love this unpopular corporation too"); } })(); saySomethingClever();
      
      





気配りのある読者が気づいたかもしれませんが、ここではimmidiate関数も使用されます。 これで、チェックは1回だけ実行されます。



自己定義関数



関数を最初に呼び出すときに、追加のアクションを実行する必要がある場合があります。 これは次のように実装できます。



 var selfDefining = function() { console.log("some really heavy initialization occured"); console.log("f*ck yeah!"); selfDefining = function(){ console.log("job done!"); } } selfDefining(); selfDefining();
      
      





この手法は、関数の外部に1つの変数を保存するのに役立ちます。これにより、関数が呼び出されたかどうかを確認できます。



カレー



この手法を使用すると、かなり一般的な機能のプライベートバージョンを作成できます。 実装は次のようになります。



 function curry( fn ){ var slice = Array.prototype.slice, storedArgs = slice.call( arguments, 1 ); return function() { var args = storedArgs.concat( slice.call( arguments ) ); return fn.apply( this, args ); } }
      
      





もちろん、nifigaはわかりにくいですが、これは正常です。 今からすべてを説明します。

メッセージを出力する関数があるとします。



 function printMessage( author, message ){ console.log( author + " say: " + message ) }
      
      





しかし、プロジェクトのこのモジュールでは、 は常に著者の価値として使用されるので、メッセージのある行のみを受け入れ、著者自身を書くよりプライベートなバージョンが非常に望ましいです。



 var printMyMessage = curry( printMessage, "me" ); printMyMessage( "I would like to tell you about birds and bees in js world" );
      
      





そして今、私たちはそれを持っています。



UPD。 ジャマイカというニックネームを持つ非常に良い人からの記事への追加



再帰関数を宣言する



たとえば、コードのヒープで使用される愚かな階乗があります。



 var factorial = function (n) { return n === 1 ? 1 : factorial(n - 1) * n; };
      
      





まあ



 function factorial(n) { return n === 1 ? 1 : factorial(n - 1) * n; };
      
      





その後、何らかの理由で必要です



 var realFactorial = factorial; factorial = function (n) { throw 'please use realFactorial instead'; };
      
      





その結果、factorial(5)およびrealFactorial(5)を呼び出すとエラーがスローされることがわかりました。 これは、 再帰呼び出し階乗は、親スコープからの変数を使用し、そこで再定義されます。 この場合、次のように関数を定義する必要があります。



 var factorial = function factorial (n) { return n === 1 ? 1 : factorial(n - 1) * n; };
      
      





まあ、混乱しないように:



 var factorial = function f (n) { return n === 1 ? 1 : f(n - 1) * n; };
      
      





すべてのようです-いつものように、例のソースコードはここからダウンロードできます



All Articles