JavaとJavaScriptのスコープの考え方は似通っているとは思いますが、もちろん違う部分もあるわけです。そんなわけで、Javaの挙動を参考にして考えると違和感を感じたスコープの振る舞いをメモしました。
ローカル変数は関数のどこで定義されても関数全体で有効になる
グローバル変数はスクリプト全体から参照できるので、関数内からもアクセスできます。なので、下記コードの実行結果は"Global"が表示されます。
// グローバル変数 var scopeName = 'Global'; function getScopeName() { document.writeln("Scope Name : " + scopeName); // Global } getScopeName();
グローバル変数と同じ変数名のローカル変数を関数内に定義した場合はローカル変数が表示されそうです。下記コードの実行結果は"Local"が表示されました。
// グローバル変数 var scopeName = 'Global'; function getScopeName() { // ローカル変数 var scopeName = 'Local'; document.writeln("Scope Name : " + scopeName); // Local } getScopeName();
なので、ローカル変数をその出力処理の後に定義した場合、これはグローバル変数が表示されそうです。
// グローバル変数 var scopeName = 'Global'; function getScopeName() { document.writeln("Scope Name : " + scopeName); // Globalになる? // ローカル変数 var scopeName = 'Local'; } getScopeName();
が、この出力結果は「undefined」になります。関数内で宣言されたローカル変数は関数全体で有効ということになるため、出力処理ではローカル変数の中身を表示しようとします。しかし、var命令は実行されていないためローカル変数の中身は未定義ということになるらしいです。へー。
varを使わずに宣言された変数はグローバル変数となる
関数内で宣言された変数は関数の外からは参照出来ない、というのがJavaでは使い慣れた規則です。例えば、下記のコードはエラー(Uncaught ReferenceError: scopeName is not defined)となります。
function getScopeName() { var scopeName = 'Local'; } getScopeName(); document.writeln("scopeName : " + scopeName); // scopeName is not defined
しかし、関数内の宣言にvarをつけていないと、どうやらグローバル変数となってしまうようで、関数の外からでも参照できてしまうようです。varの有無には気をつけないと。
function getScopeName() { scopeName = 'Local'; } getScopeName(); document.writeln("scopeName : " + scopeName); // Local
ブロックレベルのスコープは存在しない
if文の中でvarをつけて一時変数を定義したとしても、if文を抜けた先でもその変数は有効だそうです。
if (true) { var temp = 'Temp'; } document.writeln("temp : " + temp); // Temp
Functionコンストラクタの引数はグローバル変数が使われる
グローバル変数とローカル変数を同名で定義して、ローカル関数の中でFunctionのコンストラクタの引数に定義した変数を記述すると、グローバル変数の値を評価するようです。そしてグローバル変数をコメントアウトすると、定義されてないというエラーが出ます。ローカル変数は使えない。
// グローバル変数 var scopeName = 'Global'; function getScopeName() { // ローカル変数 var scopeName = 'Local'; // Functionのコンストラクタを利用して定義 var getScopeName = new Function('return scopeName'); document.writeln("Scope Name : " + getScopeName()); // Global } getScopeName();