僕らは JavaScript を知らない - 巻き上げ Hoisting
参考:
JavaScript において、変数を宣言するには var
、 let
、 const
を利用します。これらのうち、 var
let
では、初期値を指定せずに宣言した場合すべて undefined
になります。
var a; let b; console.log(a); // undefined console.log(b); // undefined
変数や関数の宣言が、自身のスコープ内のコードの一番上に来ているかのような動作を巻き上げ (Hoisting) と呼びます。例えば、次のコードを実行してみましょう。
a = 1;
var a;
console.log(a);
上記のコードを上から順に解釈していけば、 undefined
と出力されそうですが、実際には 1
が出力されます。関数宣言でも同様です:
foo(); function foo() { console.log(1); }
foo
関数の宣言前に foo
を実行しているようにみえますが、出力は 1
になります。コードの実行順に即したコードはそれぞれ次のようになります:
var a;
a = 1;
console.log(a);
function foo() { console.log(1); } foo();
このように、変数や関数の宣言をスコープ内の一番上 (今回はグローバルスコープ) にもってくることを巻き上げ (Hoisting) と呼びます。実際の JavaScript の動作としては、コード実行前のコンパイル時に宣言式を処理しているというだけで、宣言式を物理的に動かしているということはありません。
注意点として関数式は巻き上げされないため、次のコードではエラーが発生します:
foo(); // Uncaught TypeError: foo is not a function var foo = function() { console.log(1); }
変数 foo
の宣言は巻き上げられて処理されます。しかし、関数の代入はコードの実行時に処理されるため、 foo()
は undefined
を実行し、 TypeError
が発生します。コードの実行順に即して書き直すと次のようになるでしょう:
var foo; foo(); foo = function() { console.log(1); }
foo
の値が undefined
になることがよく理解できるのではないでしょうか。
また、 let
/ const
では巻き上げは起こりません。
console.log(a); // ReferenceError: a is not defined let a = 1;