if文ブロックのスコープ

次のような、あまり良い書き方ではないプログラムがあったとします。

if(condition)
  var foo=1;
else
  var foo=2;

Debug.message(foo);

これは、あまり良い書き方ではないにも関わらず、うまく動きます。ところが、ある日突然思い立って、if文に中括弧(ブロック)を付けてみるとどうでしょう。

if(condition){
  var foo=1;
}else{
  var foo=2;
}

Debug.message(foo);
スクリプトで例外が発生しました
メンバ "foo" が見つかりません

なんと、if文にブロックを付けただけで等価ではなくなってしまう!

if文のブロックの中で宣言された変数のスコープは、そのブロックの内部となるようです。しかし最初の例のように、単一の文だけの、ブロックを持たないif文はそうではありません。

他の言語を考えてみると、例えばC++では、単一の文であろうとブロックであろうと、if文の中で宣言された変数をその外で使うことはできずコンパイルエラーになります。逆にJavaScriptは、if文のブロックのなかで宣言された変数であろうと、その後に評価される式中であれば使用できます。Perlは後置ifを許しているからか、後置ではない普通のif文の場合はそもそも単一の文を与える事はできません。ブロックのみです。Rubyも文法は違いますがこのような区別はありません。

そんなわけで、単一の文のifとブロックのifが等価ではない言語は、結構珍しいのではないでしょうか。それゆえにこれは吉里吉里特有のはまりどころなのではないかと思うけれど、そもそもifの内部で宣言を行った変数をその外で使うなんてことは、常識的に考えて悪い書き方ですから、まともなプログラマにとってはどうでもいいことかもしれません。

……と書いてから気付いたけれど、Perlでuse strictを宣言した場合の後置ifと通常ifでも、TJSと同じ違いがありますね。つまり、

use strict;
my $foo=1 if(1);
print $foo;

これはおkだけど、次のはだめ。

use strict;
if(1){my $foo=1};
print $foo;