0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptのホイスティングって何!? 謎の動きを徹底解説

Posted at

「JavaScriptを学んでるんだけど、急に undefined とか出てきて意味わかんない!
なんか“ホイスティング”とか言われてもピンとこないし…正直めんどくさい!!」

そんな衝撃を受けているそこのあなた。大丈夫です、みんな最初はそう思います。
というわけで、今回は JavaScript独特の「ホイスティング」 について、ムリなくわかるようにまとめてみました。

そもそもホイスティングって何なの?(震え声)

ホイスティング(hoisting) とは、「変数や関数の宣言が、実際に書いた位置より上にあるかのように扱われる仕組み」のことです。
要するに、JavaScriptエンジンが「このコードを動かす前に、変数や関数をまとめて宣言しておこう」と裏で準備しちゃうわけですね。
そのおかげ(?)で、宣言前に変数を使っているのにエラーにはならなかったり、
逆に「エラーになるはずがないのになぜかエラーが出た…」みたいな状況が起こるわけです。

1. var のホイスティング

コード例

console.log("変数 myVar の値:", myVar);
// ここでは "undefined" と表示(なぜエラーにならない!?)

var myVar = "Hoisted!";
console.log("変数 myVar の値:", myVar);
// ここでは "Hoisted!" と表示

解説
見てのとおり、宣言より前の行で myVar を出力しているのに、エラーが起きないのは不思議ですよね。
これは JavaScriptが「varで宣言された変数」を先に確保(宣言だけ)しているから なんです。
しかし、変数が「存在」するだけで値の代入は後になるので、最初の出力は undefined、その後に "Hoisted!" が入るという流れになります。

要するに「変数名だけ先に登録しておいて、中身は後で入れる」というイメージです。
(実行したときの挙動と、コードの見た目が一致しないので、ちょっとややこしいんですよね。)

2. 関数宣言 vs 関数式

「じゃあ関数も同じなの?」と思ったら、これがまたホイスティングをさらに複雑に見せるポイントです。

(1) 関数宣言

コード例

// --- function宣言の場合 ---
hoistedFunction();  
// => "function宣言のhoistedFunctionが呼び出されたよ!" と表示される

function hoistedFunction() {
  console.log("function宣言のhoistedFunctionが呼び出されたよ!");
}

解説
function hoistedFunction() { ... } という書き方を関数宣言と呼びます。
「変数の宣言」と違って、関数の本体そのものもまとめて上に持ち上げられるため、宣言より前の場所でも関数を呼び出すことができます。

(2) 関数式(function式)

コード例

// --- function式の場合 ---
hoistedExpression();  
// => 実行時にエラー!!! ("まだ中身が入ってない!")

var hoistedExpression = function() {
  console.log("function式のhoistedExpressionが呼び出されたよ!");
};

解説
var hoistedExpression = function() { ... }; の書き方をfunction式といいます。
これは「変数に関数を代入している」だけなので、変数自体が先に宣言されるだけで、実際の「関数の中身」が代入されるのは後からになります。
結果として、宣言より前の行で呼び出そうとすると「まだ関数が入ってない!」とエラーになるわけですね。

3. let / const の場合は?

最近のJavaScriptでは、var よりも let や const を使うのが一般的です。
これらを使うとホイスティングはどうなるんでしょうか?
コード例

console.log("myLetVar の値:", myLetVar);
// => ここはエラー(ReferenceError)! 

let myLetVar = "これは myLetVar だよ";
console.log("myLetVar の値:", myLetVar);
// => "これは myLetVar だよ"

解説
var のときは undefined になっていたのに、let や const だとエラー。
これは 「宣言される前に使ったらダメ!」 というルールがあるからです。
こうすることで、「うっかりミスで宣言前に変数を使っちゃった!」みたいな状況を減らせるわけですね。
いわば、安全装置みたいなものと考えるといいかもしれません。

まとめ

ホイスティングとは

  • 実行前に変数や関数宣言をまとめて上に持ち上げてしまう(hoisting)JavaScriptの仕組みのこと
  • varの場合
    • 変数の「存在」だけが先に作られるため、宣言前に呼び出すと undefinedtとなる
  • function宣言の場合
    • 「関数本体」も含めて先に読み込まれるので、宣言前から呼び出せる
  • function式 (var x = function() {...})の場合
    • 変数だけ先に用意される。関数本体は後から代入されるので、宣言前の呼び出しはエラーとなる
  • let や constの場合
    • 宣言される前に使うとエラーになる
    • 「宣言前に使っちゃダメ!」が明確になっているので、安全性が高い

要するに、「宣言はなるべくコードの上部にまとめる」 ことやですね。
「let と const で変数を管理する」 ことで、ホイスティングによる混乱を減らすことができます。

おわりに

ホイスティングって最初は「えっなんで?」となりがちですが、JavaScriptをちゃんと理解するうえで避けては通れないポイントです。
「思った通り動かないぞ?」というときは、「あ、ホイスティングのせいかな」と疑ってみましょう。
そのうえで、宣言位置を見直してみたり、let / const を使うようにしてみたりすると、すっきり解決するかもしれません。

そんなわけで、ホイスティングをざっくり解説してみました。
実際にコードを書いてみると「本当に undefined なの?」とか「まじでエラーになるの?」と体感できるはず。
ぜひ試してみて、「おお、こういうことだったのか!」と納得してもらえたら嬉しいです!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?