はじめに
アウトプットが苦手な自分が練習の一環として記事を書いてみる。
第六回目です。
今回はJavaScript独特の挙動であるホイスティング(巻き上げ)について書いていきます。
ホイスティング(巻き上げ)とは?
ホイスティングとは 変数や関数の宣言は常にコードの先頭で行われたことにする という挙動のことです。
以下を例に見ていきます。
function a() {
console.log('aが実行されました')
}
a();
// 実行結果
aが実行されました
上記は「関数を定義」しその後「関数の実行」を行っているので結果はaが実行されました
が出力されました。
ここまでは問題ないと思います。
では次は「関数を定義」と「関数の実行」の順番を入れ替えるとどうなるでしょうか。
a();
function a() {
console.log('aが実行されました')
}
// 実行結果
aが実行されました
結果は順番を入れ替えてもaが実行されました
が出力されました。
プログラムは基本的に上から順に処理が行われるためエラーになりそうですが、問題なく動作しています。
これがホイスティングによる変数や関数の宣言は常にコードの先頭で行われたことにする挙動です。
変数を使ったホイスティング
ホイスティングにはもう一つ特徴があります。
それは定義のみが巻き上げられ、初期化は巻き上げられないというものです。
次の例を見ていきます。
function a() {
console.log(x);
var x = 0;
}
a();
// 実行結果
undefined
一見「0」が出力されそうですが、結果はundefined
となりました。
これは宣言のみが巻き上げられ、コンソールログ出力時の段階では初期化が行われないため結果「undefined」が出力されました。
以下のように初期化処理の後にコンソールログを出力をすることで「0」が出力されます。
function a() {
console.log(x); // undefined
var x = 0;
console.log(x); // 0
}
a();
よくありそうなミス
最後にグローバル変数を出力しようとしたが、意図せずブロックスコープ内に同名の変数を宣言してしまった場合、以下のようになります。
var x = 0;
function a() {
console.log(x);
var x = 10;
}
a();
// 実行結果
undefined
結果はundefined
になりました。
これはブロックスコープ内の宣言が巻き上げられたことで参照する変数がブロックスコープ内の変数「x」となってしまいました。
そして「x」は初期化されていないため、0を出力するつもりが結果undefinedが出力されてしまったのです。
まとめ
以上になります。
ホイスティングはJavaScript特有の挙動なので意識していないと予期せぬ挙動になってしまいます。
対策としては変数の宣言はなるべく先頭に行うのが良いと思います。
参考になれば幸いです。
参考サイト
https://developer.mozilla.org/ja/docs/Glossary/Hoisting