はじめに
悪名高きvar
ですが、その理由の一つに「巻き上げ(Hoisting
)」があると言われています。
その「巻き上げ」について誤解していたことが多々あったので共有です。
「巻き上げ」は公式の用語ではない
「巻き上げ」は ECMAScript 仕様書で規範的に定義されている用語ではありません。
let
const
の巻き上げ
「var
ではなく、let
const
を使え」とよく言われます。
てっきり、let
const
はvar
の欠点-巻き上げ-を持たないものと思っていました。
どうも、そう単純な話でもなさそうです。
俗な言い方をすれば、以下のような動作はすべて巻き上げと見なされます。
- スコープ内の宣言行よりも前で変数の値を使用すること。(「値の巻き上げ」)
- 変数がスコープ内の宣言行よりも前で参照しても
ReferenceError
が発生せず、値が常にundefined
であること。(「宣言の巻き上げ」)- 変数の宣言により、スコープ内のそれが宣言された行よりも前の動作が変化すること。
- 宣言の副作用として、宣言を含む残りのコードの評価が行われる前に、宣言の副作用が発生すること。
上記の 4 つの関数宣言はタイプ 1 の動作で巻き上げが行われます。
var
宣言はタイプ 2 の動作で巻き上げが行われます。let
,const
,class
宣言(まとめて字句宣言とも呼ばれる)はタイプ 3 の動作で巻き上げが行われます。import
宣言はタイプ 1 とタイプ 4 の動作で巻き上げが行われます。
また、同じサイトの別ページにはこんな記述もありました。
let
とconst
が巻き上げられるかどうかは、定義の議論の余地があります。変数宣言の前にブロック内で変数を参照すると常にReferenceError
が発生します。ブロックの始まりから宣言が処理されるまで、変数は「一時的なデッドゾーン」にあるからです。
議論の余地がある、という感じですね。
「巻き上げ」が仕様書で定義されている用語でないために起こることですね。
「一時的なデッドゾーン」について知りたい方はこちら
おわりに
以上、巻き上げについて誤解していたことの共有でした。
次は何を書こうかしら・・・