Function Scope and Block Scope
関数内で変数を宣言すると、その変数は関数内で束縛されて、関数外にアクセスできないようになります。 var
は関数スコープにアクセスするための変数を定義するキーワードです。
さて、let
や const
を使ってもエラーになるのに、なぜ var
だけ関数スコープに関連付けられるのかと思うかも知れませんね。 実は、let
と const
はブロックスコープの定義に使われていて、ES6 以前の JavaScript にはブロックスコープや let
と const
はありませんでした。
ブロックスコープは
if
やswitch
条件、for
やwhile
ループ内の領域のことを指します。 簡単に言うと、{{curly brackets}}が表示されているときは、ブロックである。
例を見てみよう。
さて、どのログコマンドも動作しないと思うかもしれませんが、var の場合はそうではありません。if
や switch
条件、for
および while
ループ内で var で定義した変数はグローバルにアクセスでき、グローバルスコープの一部となりますので、let
および const
と併用するほうがよい習慣なのです。
Lexical Scope
最後に、この記事の真の目的に到達しました。 まあ、スコープについての長い議論を省略することもできましたが、個人的には、それを中心とした重要なコンポーネントを知らずに、レキシカル スコープを理解することはできないと思います。
簡単に言うと、子スコープが親スコープで定義された変数にアクセスできることを意味します。 たとえば、ある関数を定義してその内部で変数を宣言し、まったく同じ関数内で別の関数を定義した場合、レキシカル スコープにより、内部の関数内でその変数を使用できるはずです。
この例からわかるように、outerFunction()
で宣言した変数には innerfunction()
でアクセスしています。 変数を解決するために、JavaScript は最も内側のスコープから始まり、探していた変数を見つけるまで外側に検索します。 上記の例では、Javascript はまず innerFunction()
内の変数を検索し、見つからなかったら、outerFunction()
レキシカル スコープは、コードから変数の値を簡単に把握できるので優れていますが、ダイナミック スコープでは、変数の意味が実行時に変更されることがあるので、理解するのが難しくなっています。
さて、レキシカル・スコープはどういうものか理解できたと思いますが、次は実際にレキシカル・スコープが使われるクロージャを見てみましょう。