Buno Journals

It's what I do that defines me.

JavaScript: 変数宣言の巻き上げ

変数宣言と初期化

jsでは通常、以下のように変数を宣言し、値を代入する(初期化)

var str; // 宣言
str = 'hello';  // 値を代入(初期化)

一行で書くこともできる。

var str = 'hello';

宣言の巻き上げ

jsでは変数の宣言は、関数スコープの先頭に巻き上げられる。

例えば、以下のようなコードがあったとする。

function sayHello() {
  console.log(str);
  var str = 'hello';
}

これは、次のように動作する。

function sayHello() {
  var str; // 宣言、undefinedの値が割り当てられる
  console.log(str);  // 出力: undefined
  str = 'hello'; // 代入(初期化)
}

つまり、

  • 変数宣言は、関数スコープの先頭に巻き上げられ、その変数にはundefinedの値が割り当てられる。
  • 変数の代入(初期化)の位置は変わらない。

スコープチェーンの上昇

JavaScriptエンジンは、変数宣言をローカルスコープからグローバルスコープに向かって調べていく

以下のコードの実行を考える。

var str = 'hello';
function sayHello() {
  console.log(str); // 出力: 'hello'
}
sayHello();

関数sayHelloを実行して、console.log()が変数strを要求すると、JavaScriptエンジンはまず変数strがローカルスコープで宣言されているかを調べる。 この場合、変数strはローカルスコープで宣言されていないので、次にグローバルスコープを調べて、宣言を見つけて値を返す。

では、次のコードはどうなるか。

var str = 'hello';
function sayHello() {
  console.log(str); // 出力: undefined
  var str;  // ローカルスコープでも変数宣言
}
sayHello();

変数strがローカルスコープでも宣言されている。 この宣言は関数先頭に巻き上げられるので、グローバルスコープを調べる前に、この宣言を見つけて出力する。 ローカルスコープでは宣言のみにで初期化はされていないので、出力はundefinedだ。

参考

シングルページWebアプリケーション ―Node.js、MongoDBを活用したJavaScript SPA

シングルページWebアプリケーション ―Node.js、MongoDBを活用したJavaScript SPA