「JavaScript/変数」の版間の差分

削除された内容 追加された内容
→‎変数のスコープ: 「関数スコープをもつ」の意味の説明が抜けている。
207 行
変数が値を保持する範囲のことを変数の「スコープ」といいます。JavaScriptでは、関数と、if文・for文とでは、スコープが異なります。
 
このことを、<code>var</code>で宣言された変数は'''関数スコープ'''を持つ、とも言います。一方、<code>if</code>文や<code>for</code>文などのブロックはスコープを作りません。
 
まず、関数の場合のスコープのコード例を示します。
 
<syntaxhighlight lang="JavaScript">
240 ⟶ 242行目:
上記の''x''は関数の中と外では違う変数になるので、外側の''x''の値は冒頭の<code>var x = 1;</code>のままです。
 
一方で、下記コードの''x''はブロックの中と外で同じ変数を指すので(varは関数スコープを持つが、しかしif文のスコープは持たないので)、''x''の値が変わってしまいます。
 
<syntaxhighlight lang="JavaScript">
274 ⟶ 276行目:
 
これは次のような場合に問題となります。
1 秒間隔で 0, 1, 2 と出力したいプログラムを書く場合、下記のようにコードを書いても、「333」となってしまい、失敗します。
 
<syntaxhighlight lang="JavaScript">
<script>
// 1 秒間隔で 0, 1, 2 と出力したい
 
for (var i = 0; i < 3; i++) {
285 ⟶ 288行目:
}
 
// -- するはずがしかし、実際に出力されるのは 「333」
</script>
</syntaxhighlight>
301 ⟶ 304行目:
// -- するはずが実際に出力されるのは 3, 3, 3
</SyntaxHighlight>
 
-->
結果は「333」となり表示まで期待通りの「012」1秒ほど経過しはなってくれせん
 
なお、表示までに1秒ほど経過します。
 
 
2020年現在なら、この問題は<code>let</code>キーワードで容易に解決できます。ECMA2015でletキーワードが導入されました。
 
<syntaxhighlight lang="JavaScript">
<script>
// 1 秒間隔で 0, 1, 2 と出力したい
 
// for の次が var i = 0 でなく let i = 0 に変わっている
for (let i = 0; i < 3; i++) {
setTimeout(function() {
document.write(i);
}, 1000);
}
 
// -- 実際の出力は「012」となり、成功。
</script>
</syntaxhighlight>
 
 
なお、ECMAScript 5以前はletキーワードが無かったので、上述の問題を解決するには、ECMAScript 5以前は次のように無理やり関数スコープを作るしかありませんでした。
 
<syntaxhighlight lang="JavaScript">
377 ⟶ 402行目:
<code>var</code>にはこういった問題があるのですが、かといって「常に関数の先頭で全部の変数を宣言するようにし、途中で<code>var</code>を使わないようにする」というのでは、昔の[[C言語|C]]みたいで、あまりに退屈です。ハッカーは問題を解くのに適した言語を''作る''べきで、言語に人間が合わせるべきではありません。そもそもの問題は<code>var</code>がブロックスコープをもたないことにあるのだから、ブロックスコープをもつ<code>var</code>を発明するのが筋です。
 
※ 検索用アンカー {{anchor|let}}
==== let ====
var キーワードは関数スコープを持つのに、if文やfor文などのスコープを持たないので、不便な場合があったり、JavaScriptに馴れないプログラマーに混乱を引きおこす場合がありました。
<code>let</code>キーワードで宣言された変数はブロックスコープをもちます。さらに<code>for</code>文の条件式で<code>let</code>で宣言された変数は、<code>for</code>文のブロックの内側にしか見えません。
 
ECMA2015から新たに導入された<code>let</code>キーワードで宣言された変数はブロックスコープをもちます。関数ブロックに限らず、if文でもfor文でも、あるいは単独の<code>{ }</code> でも、letキーワードは必ずブロックスコープを持ちます。
 
for文の条件式は、見た目は<code>{ }</code> は使われていないですが(条件式の部分のカッコは見た目は<code>( )</code> なので)、条件式の部分も実質的にfor文のスコープを持つように実装されています。
 
<code>let</code>キーワードで宣言された変数はブロックスコープをもちす。さらにり、<code>for</code>文の条件式で<code>let</code>で宣言された変数は、<code>for</code>文のブロックの内側にしか見えないように実装されていせん
 
<syntaxhighlight lang="JavaScript">
394 ⟶ 425行目:
</syntaxhighlight>
 
ただしFirefox 39までの実装にはバグがあり、<code>for</code>の条件式で<code>let</code>で宣言された変数が<code>for</code>の外に見えてしまっていました<ref>[//bugzilla.mozilla.org/show_bug.cgi?id=854037 Bug 854037 - fresh binding per iteration of C-style for-let]</ref>。[[:w:GNU IceCat|Gnuzilla Icecat]]の最新版はいまだに {{いつ|date=2020年7月}} 38ですので注意してください。
 
== 脚注 ==