180
175

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

いつかあなたが絶対に引っかかる、ある一つのJavaScriptの罠

Posted at

JavaScriptは、シンプルな仕様が美しい言語です。
しかしながら、シンプルが故に、一度罠にハマると見つけにくくて抜け出すのが大変です。

罠にハマった時に、すぐに抜け出せるように、簡単な例で抑えておきましょう。

ある一つのJavaScriptの罠が入ったコード

罠が入ったサンプルコードがこちら。

sample
for (var i = 0; i < 3; i++) {
	setTimeout(function() {
		console.log(i);
	}, 0);
}

コンソールに i という変数を出力しています。

出力はどのようになりますか?

これ、実行したらどのような出力になると思います?
0、1、2と答えたあなた。わたしはそんな素直なあなたが大好きです。
2、2、2と答えたあなた。素晴らしい。JavaScriptを極めてますね!ただ、不正解。ケアレスミス。

出力の答え

こたえは3、3、3。不思議ですね。
さて、なぜこうなるかを解説しましょう。

罠の解説

罠の本質。クロージャとsetTimeout

JavaScriptにはクロージャという仕組みがあります。簡単に言うと、変数が生きつづける仕組みです。
これとsetTimeout という処理を後から実行する仕組みのコンビネーションでこれが発生します。

処理の解説

for 分の中で変数 i は0、1、2と増えて行きます。
しかしながらconsole.logへの出力はsetTimeout の中で行われるため、for文のループが回っている最中は実行されません。なのでconsole.log(i)の i は、ループ中はまだ値として解釈されません。
iが3になってループが終わり、setTimeout が実行される順番が来るとそこで始めて i の中身が出力されるので、出力は3,3,3となるのです。

予言しよう!あなたはいつか、この罠を踏む。

クロージャもsetTimeoutも、JavaScriptには欠かせない重要な機能です。
しかしながら、よくよく理解していても、この罠をちょくちょくふむことがあります。
「あれー。なんかループの中のデータがおかしい!」とか、「ん?変数の値が上書きされてる!」とかいう事態が起きたら、この投稿を思い出してください。
サンプルコードは、ループとsetTimeout で例にあげましたが、この罠はその他の組み合わせ、クリックと通信処理など、他の組み合わせでも発生します。

180
175
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
180
175

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?