「持ち上げる」という考えは、何が起こっているのかを理解するための悪い方法です。言い換えれば、私の意見では、「巻き上げ」は巻き上げの悪い説明です。
実際に起こっているのは「巻き上げ」ではありません。実際に起こっていることは、javascript がコンパイル フェーズと評価フェーズの 2 つのフェーズでコードを実行することです。JavaScript コミュニティはこの現象を「ホイスト」と呼んでいますが、ほとんどの人はなぜホイストをホイストするのか理解できていません。
実際に何が起こるかは、巻き上げのアイデアよりも簡単に説明できます。ルールは次のとおりです。
Javascript は常にトップダウンでコードを解析します。コードを並べ替えることはありません (ホイストすることはありません)。
実行には、コンパイルと評価の 2 つのフェーズがあります。
すべての宣言はコンパイル段階で処理され、コンパイル段階では式は評価されません (「評価」は評価段階で行われるため)。
評価が必要なすべての式とその他のものは、評価フェーズで処理されます。
ルール 1 を思い出してください。すべての解析はトップダウンで行われ、バックトラッキングや巻き上げはありません。
あなたの例を取り上げて、javascript のコンパイルと評価フェーズを念頭に置いて理解しようとしましょう。
var myName = "Richard"; // Variable assignment (initialization)
function myName () {
console.log ("Rich");
}
console.log(typeof myName); // string
コンパイル段階では、インタプリタは変数の宣言を認識します。この変数にメモリ領域を割り当て、値を割り当てますundefined
。
コンパイル段階では、インタープリターは関数の宣言を認識します。また、関数名が変数名を隠していることにも注意してください。したがって、関数「myName」が作成されます (これは、この時点で変数myName
が関数を指していることを意味します)。
コンパイル フェーズが終了します。いよいよ評価フェーズに入ります。
評価フェーズでは、インタープリターは文字列を に割り当てていることを確認しますmyName
。
宣言はコンパイル段階で処理されるため、関数宣言に到達したときに評価するものは何もありません。
評価フェーズでは、インタプリタは typeof を console.logging するのを見ますmyName
。最後に割り当てられたのは文字列だったので、「文字列」と表示されます。
myName
文字列の割り当てを削除すると、typeof "function" になることに注意してください。その場合、最後に割り当てられるのは宣言された関数だからです。
実行の 2 つのフェーズによって引き起こされるその他の微妙な点については、この関連する質問を参照してください: JavaScript 関数の宣言と評価順序