マイナー・マイナー

隠れた名作の発掘が生きがい。

違和感を感じるJavaScriptのスコープの振る舞い


スポンサードリンク

JavaJavaScriptのスコープの考え方は似通っているとは思いますが、もちろん違う部分もあるわけです。そんなわけで、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();


関連:JavaScriptの関数は3つの方法で定義できるらしい