javascriptのスコープを✅

ほんとに1週間が経つのが早すぎますね。明後日までにエラーを改修してRUNTEQ内リリースをします。#決意

今回は、javascriptのスコープに関して学習していきたいと思います。

スコープとは

スコープとは変数の名前や関数などの参照できる範囲を決めるもの。 スコープの中で定義された変数はスコープの内側でのみ参照でき、スコープの外側からは参照できない。

スコープの役割

変数名の競合を避ける

もしスコープがなければ、プログラム全体で使われるすべての変数に、一意な名前を付けて衝突を避けなければならなくなる。一方でJavaScriptにはスコープがあるため、その必要がない。

メモリの消費を避ける

JavaScriptには、使われなくなったメモリ領域を自動的に解放するガベージコレクションという仕組みがあるそう。これによって、無駄なメモリの消費を回避しる。

もしスコープがなければ、すべての変数がグローバルに属することになる。

そして、グローバルに属する変数はプログラムから参照され続けるため、ガベージコレクションされない。

つまり、ページを閉じるまでの間ずっと、不要なメモリ領域を確保し続けるという「メモリリーク」が起きてしまう。

実際にはスコープがあるため、関数の実行が終われば、そのスコープに属する変数は不要とみなされ、ガベージコレクションの対象となる。

スコープの種類

スコープは、グローバルスコープとローカルスコープの2種類が存在している。

さらに、ローカルスコープは、関数スコープとブロックスコープに分類できる。

├── グローバルスコープ
└── ローカルスコープ
    ├──関数スコープ
    └──ブロックスコープ

グローバルスコープ

プログラムのトップレベルで宣言された変数はグローバル変数になり、プログラム全体のどこからでもアクセス可能なグローバルスコープを持つようになる。

var scope = 'global';

# トップレベルからのアクセス
console.log(scope); // -> global

# 関数内からのアクセス
(function () {
  console.log(scope); // -> global
})();

ローカルスコープ

グローバル変数以外のすべての変数。関数スコープとブロックスコープに分類される。

関数スコープ

関数内で宣言された変数は関数外からアクセスする事ができない。

function sake() {
    const age = 20;
    # sake関数のスコープ内から`age`は参照できる
    console.log(age); // => 20
}
sake();
// fn関数のスコープ外から`age`は参照できないためエラー
console.log(age); // => ReferenceError: age is not defined

{}で囲まれた関数内の変数は関数外で呼び出すとエラーになる。

ブロックスコープ

{}で囲まれたスコープのこと。

ブロックないで定義した変数へ、スコープ外からアクセスする事ができない。

# ブロック内で定義した変数はスコープ内でのみ参照できる
{
    const age = 20;
    console.log(age); # => 20
}
# スコープの外から`x`を参照できないためエラー
console.log(age); // => ReferenceError: age is not defined

ループ文でブロックスコープを作成することもできる。

const array = [1, 2, 3, 4, 5];
 # ループごとに新しいブロックスコープを作成する
for (let element of array) {
    # forのブロックスコープの中でのみ`element`を参照できる
    console.log(element);
}
# ループの外からはブロックスコープ内の変数は参照できない
console.log(element); 
# => ReferenceError: element is not defined

宣言文とスコープ

関数の仮引数とvarは関数スコープだけを生成し、letconstは関数スコープとブロックスコープの両方を生成する。

letやconstを使わずに宣言文を作成すると自動的にグローバルスコープになってしまう。グローバルスコープを作りすぎるとグローバル汚染が起きてしまう

function fn() {
  # 関数スコープの中で宣言文を付けずに変数宣言
  scope = 'local';
}
fn();

# グローバルスコープとなり、関数スコープの外からアクセスできてしまう
console.log(scope); // -> local

グローバル汚染

.グローバル環境を時に意味のない変数で汚染すること。グローバル汚染が進むと下記のような弊害が起きる。

  • サードパーティプラグインを読み込んだ時の変数の衝突
  • チームメンバーが書いたコードとの名前衝突
  • 昔書いた自分のコードで使った変数との衝突

まとめ

  • 関数やブロックはスコープを持つ
  • スコープはネストできる
  • もっとも外側にはグローバルスコープがある
  • スコープチェーンは内側から外側のスコープへと順番に変数が定義されているか探す仕組みのこと

関数とスコープ

JavaScriptのスコープ総まとめ | 第1回 スコープの種類とその基本 | CodeGrid