JavaScriptの巻き上げ(hoisting)とは?JS開発者なら知っておきたい仕組み。

JavaScriptの巻き上げ(hoisting)とは?JS開発者なら知っておきたい仕組み。

この記事では、JavaScriptの特徴的な仕組みである巻き上げについて出来るだけシンプルに説明したい。

巻き上げ(hoisting)はJavaScript開発者として技術面接を受ける際にはよく尋ねられる質問のひとつだ。

JavaScriptのコンパイルの仕組みを理解するうえでの助けにもなるので、ぜひ覚えておこう。

JavaScriptの巻き上げ(hoisting)とは?

まずは巻き上げについて簡単に説明したい。

JavaScriptエンジンはコードを実行する前に、グローバルな実行コンテクストを作成している。

実行コンテクストには「生成」と「実行」の2つのフェーズがあり、生成のフェーズにおいてJavaScriptエンジンは変数や関数の宣言をコードの最上部に移動する。

この機能のことを巻き上げ(hoisting)と呼ぶ。

「変数や関数の宣言」をコードの上部に移動するものの変数の代入は行われないという点に注意が必要だ。

変数の巻き上げ

例として以下のコードを考えてみる。

console.log(myVar);
var myVar = 99;

このコードを実行した場合は出力は「undefined」となる。

変数myVarは巻き上げにより宣言されているものの「99」はまだ代入されていないために出力はundefinedとなる。

ただし、変数がletであった場合は変数がHeapメモリに追加されるものの初期化は行われない。

そのため、以下のようなコードを実行する場合は以下のようなエラーが出力される。

console.log(myVar);
let myVar = 1;
Uncaught SyntaxError: Identifier 'myVar' has already been declared

関数の巻き上げ

JavaScript関数も変数と同様に巻き上げされる。

以下の例では、getFullName関数が定義より前に呼び出されているが、巻き上げにより実行コンテクストにおいては関数の定義が呼び出せれるために関数は問題なく呼び出すことができる。

var firstName = 'Taro';
var lastName = 'Yamada';

let result = getFullName(firstName, lastName);
console.log(result);

function getFullName(fn, ln) {
  return fn + ' ' + ln; 
}

ただし、関数が関数式(FuctionExpression)やアロー関数(arrow function)では以下のようなエラーが発生するので注意が必要だ。

var getFullName = function(fn, ln) {
return fn + ' ' + ln;
}
var getFullName = (fn, ln) => fn + ' ' + ln;
Uncaught TypeError: getFullName is not a function