【JS学習その②】JavaScriptにおけるスコープ


JS学習シリーズの目的

このシリーズは、私ジャックが学んだJavaScriptのメカニズムについてアウトプットも兼ねて、
皆さんと知識や理解を共有するためのものです。
(理解に間違いがあればご指摘いただけると幸いです)

用語の定義

  • 実行コンテキスト・・・ コードを実行する際の文脈・状況(グローバルコンテキストと関数コンテキスト、evalコンテキストが存在する)
  • コールスタック・・・実行中のコードがたどってきたコンテキストの積み重ね
  • ホイスティング・・・コンテキスト内で宣言した変数や関数の定義をコード実行前にメモリーに配置すること(宣言の巻き上げ)
  • スコープチェーン・・・スコープが複数階層で、連なっている状態

スコープとは

「実行中のコードから値と式を参照できる範囲」

スコープは、実行中のコードからホイスティングされた値や式を参照できる範囲のことをいいます。
ホイスティングされている場所や書き方によって、参照される値や式は変わってきます。

スコープの種類

  • グローバルスコープ
  • スクリプトスコープ
  • 関数スコープ
  • ブロックスコープ
  • モジュールスコープ

上記の5つのスコープ存在します。
モジュールスコープに関しては、モジュールを理解している必要があるので、今回は省略します。

グローバルスコープ

グローバルスコープには、jsファイルの直下に書かれた"var変数"と"functionで宣言された関数"など
があります。
上記の"var変数"と"関数"は、グローバルオブジェクト(windowオブジェクト)の中に格納され、
グローバルスコープは、そのファイル内のどこからでもアクセスできます。
このことから、グローバルオブジェクトそのものがグローバルスコープと言うこともできます。
基本的にグローバルスコープはwindowオブジェクトを省略して記述し、記述方法が次に説明する
スクリプトスコープとほぼ同じなので、スクリプトスコープもまとめてグローバルオブジェクトと呼ばれることもあります。

main.js
var a = 0;
function b() {}

スクリプトスコープ

スクリプトスコープには、jsファイルの直下に書かれた"const定数"や、"let変数"などがあります。

main.js
const a = 0;
let b = 0;

関数スコープ

関数スコープとは、宣言された関数の{}(波括弧)の中のスコープのことを指します。

main.js
function sample() {
    let a = 0;
    console.log(a);
}

sample();

上のコードのように、sample()の中で宣言した変数"a"は、sample()関数内のconsole.log()で扱えます。

main.js
function sample() {
    let a = 0;
}

console.log(a);

しかし、sample()の中で宣言した変数"a"を関数スコープの外で使おうとすると、エラーが出ます。
関数スコープの外なので参照できる範囲の外ということですね。

ブロックスコープ

ブロックスコープは、{}(波括弧)の中のスコープのことを指します。
基本的には、関数スコープと似ているのですが、

  • 前述した関数スコープはブロックスコープの影響を受けない
  • var変数はブロックスコープを無視する

上記に気を付けてください

main.js
{
    let a = 0;
    console.log(a); /*正常に動作*/

    let b = 1;


    function sample() {
        let c = 2;
        console.log(c);
    }

    sample(); /*正常に動作*/

    var d = 3;
}

console.log(b); /*エラー*/
sample(); /*正常に動作*/
console.log(d); /*正常に動作*/

したがって上記のようにコードを書いた場合、コメントした内容の結果になります。

おまけ(varについて)

今回の記事でちょくちょくでてきたvar変数は、グローバル変数といって、様々なスコープを無視して
参照できるので、現在のJavaScriptでは非推奨となっています。
できるだけ、constやletで変数は定義するようにしましょう。