javascriptの即時関数について質問します。

Writer: admin Type: 友人関係の悩み Date: 2019-03-06 00:00
javascriptの即時関数について質問します。$('#button').on('click', function() { test(); }); function test(){ console.log("test") setTimeout("test2()",1); } function test2(){ console.log("test2"); }上記のコードなのですが、test()内のtest2()を呼ぶときに下記の3つのどれでも呼ぶことができます。setTimeout("test2()",1);setTimeout(test2(),1);setTimeout(test2,1);しかし、全部のコードを下記のように即時関数に入れると(function () { $('#button').on('click', function() { test(); }); function test(){ console.log("test") setTimeout("test2()",1); } function test2(){ console.log("test2"); } }());setTimeout("test2()",1);この場合だけエラーになってtest2()を呼べません。どういう原理なのでしょうか?共感した0###> setTimeout("test2()",1);この書き方は一度、文字列をソースコードとして解析する必要があり、遅い書き方なので、今すぐ捨ててください。メリットが皆無なので、この書き方をする理由はありません。私も普段、回答を書くにあたり、ちょっと書き方としてどうかなと思うことでも、個性の範疇ということで黙認する場合が数多くあります。しかし、これについては明らかに問題のある書き方なので、二度と使わないでください。エラーで動作しない理由は、文字列として解析されたソースコードが、グローバルスコープで実行されるからです。test2関数は即時関数のローカルスコープにあるので、外から呼び出そうとして失敗しています。関数内で定義したローカル変数に、関数の外からアクセスできないのと同じ現象です。> setTimeout(test2(),1);> setTimeout(test2,1);この2つの処理は等価ではなく、動作として明らかに異なるので、明確に区別できるようになりましょう。関数は括弧を付けることで実行されます。ですから、前者はsetTimeoutのタイマーにセットされる前に、test2関数が即座に実行されてしまいます。test2関数の返り値はundefinedですから、setTimeout(undefined, 1);最終的にこのようになります。test2関数の実行という面から見ると、1ミリ秒であれば違いは感じられないと思いますが、秒単位、あるいはそれ以上のタイマーをセットしようとすると、確実に影響が出ます。> setTimeout(test2,1);ということで、現代のJavaScriptでは、この書き方一択です。第1引数には関数オブジェクトを渡す、と覚えてください。繰り返しになりますが、括弧を付けると実行されてしまうので、括弧を付けずに渡します。ナイス0
###原理が分かりやすかったです。ありがとうございました###1) setTimeout("test2()",1);2) setTimeout(test2(),1);3) setTimeout(test2,1);2)は参照して実行、3)は参照ですが、参照した時(setTimeout実行時)にclickの関数内にtest2が存在するので参照、実行することが可能です。1)の場合setTimeout時に文字列内は評価されず、関数のスコープを外れて1ms後にevalで評価されます。その時点でのスコープは関数内ではなくグローバルになりtest2が存在しないので実行することができません。一番外側に置けば実行できます。ちなみに1)~3)を実行した場合は1) eval("test2()")を1ms後に実行されるように登録2) test2()実行2) test2()の戻り値undefinedを1ms後に実行されるように登録(または登録しない)3) test2を1ms後に実行されるように登録1ms後・eval("test2()")実行・undefined実行(何も実行されない)・test2実行となります。実行順では、1) ~ 3) をtest1~3とすると、test2,test1,test3の順になります。ナイス0
###setTimeout("test2()",1);この書き方は推奨されていない書き方となっていますsetTimeout(test2,1);通常はこちらで書きます。(setTimeoutでは引数指定不可の為)こちらを参考にされるとわかりやすいかと思います。https://developer.mozilla.org/ja/docs/Web/API/WindowTimers/setTimeo...ナイス0

 

TAG