1
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?

More than 3 years have passed since last update.

JavaScriptのHoistingについてメモ

Posted at

この記事について

Hoistingができるタイプの変数とできないタイプの変数があるので整理する。
■Hoistingとは
宣言をする前でもその変数を使えることができる仕組み

変数のタイプ

① 関数宣言(Function Declaration) (関数に名前があるタイプ)
例)function calc(a, b) {return a + b }
② varでの変数宣言
③ const や letでの変数宣言
④ 無名関数(Function expression or arrow function) (関数に名前がないタイプ)
例)const calc = function(a, b) { return a + b }

Hoistingができるのは...

① 関数宣言

関数宣言の書き方では、宣言する前に関数を呼んでいるのに、ちゃんと戻り値5で返ってくるんです。(Hoistingが機能する)

example1
console.log(calc(2, 3));

function calc(a, b) {
  return a + b;
}

コンソール上でのログ↓
スクリーンショット 2021-04-15 13.23.57.png
Hostingによって宣言前でもエラーにならず動くのですね。

② varで宣言した変数

変数を定義する前にcalc変数を使ってみます。

example2
console.log(calc);
var calc = 2 + 3;

コンソール上の結果はこちら
スクリーンショット 2021-04-15 13.33.18.png
エラーにはならないものの、undefinedで結果が表示されます。

③letやconstで宣言した変数

②と同じコードをletで書くと

example3
console.log(calc);
let calc = 2 + 3;

コンソール上の結果はこちら
スクリーンショット 2021-04-15 13.35.48.png
エラーになりますね。
これはletやconstには、Temporal Dead Zone(TDZ)が適用されるから。
TDZは、そのスコープ内で、使いたい変数が定義される(この場合let calc = 2+3)以前に書かれたコードに対してはその変数は使えないよという意味。
なので上記の例では、「initializationの前には'calc'は使えません」ってエラーが出ています。

④無名関数

①と同じコードを無名関数で書くと

example4
console.log(calc(2, 3));

let calc = function (a, b) {
  return a + b;
}

console.logで結果を確認すると、エラーになっています。
スクリーンショット 2021-04-15 13.23.28.png
③で見たエラーと同じですね。letで書いているのでTDZが適用されています。

ちなみに、無名関数をvarで書くとこのようなエラーになります。
スクリーンショット 2021-04-15 13.30.20.png
②で見た例では、var宣言したものはエラーにならずundefinedと表示されました。
これは、varで定義するとundefinedとなりますが、undefinedという名前の関数のようになってしまい、「calc is not a function」とエラーが出てしまっています。

Hoistingが適用されるとこんなことにも...

example5
if(!num) delete();

var num = 10;

function delete() {
  console.log(`deleted!`);
}

↑はvarの定義をif文より上に書けば問題ないのですが、もし間違えて下に書いてしまった時の例です。

if文で0の初期値はfalseなのを利用して「!でfalse->trueにして0だったらdelete()を実行、0以外の数字だとfalseになりdelete()は実行しない」という意図で上記コードを書いたとします。
「numは10が入るのでdelete関数は動かない」なんて思ってしまったらバグになってしまいます。varで定義されているためHoistingが適用されて最初のif文でのnumはundefinedが入るんです。
undefinedの初期値はfalseなので、!で反転してtrueになり、delete関数が動きコンソール上に「deleted!」と表示されてしまいます。
一方constやletで書いていたとするとTDZが適用されてエラーになってくれます。

感想

letやconstを使っているならエラーが出るので大丈夫ですが、varを使用して意図せずHoistingが適用されりすると見つかりにくいバグができたりするのかなーと思いました。
Hoistingの仕組みを知っているとバグ調査の時も、「varで書かれてるからもしやHoistingが適用されているのかな?」と疑ってみることもできるので、大事な知識だと感じました。

1
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
1
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?