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
は関数スコープだけを生成し、let
とconst
は関数スコープとブロックスコープの両方を生成する。
letやconstを使わずに宣言文を作成すると自動的にグローバルスコープになってしまう。グローバルスコープを作りすぎるとグローバル汚染が起きてしまう
function fn() {
# 関数スコープの中で宣言文を付けずに変数宣言
scope = 'local';
}
fn();
# グローバルスコープとなり、関数スコープの外からアクセスできてしまう
console.log(scope); // -> local
グローバル汚染
.グローバル環境を時に意味のない変数で汚染すること。グローバル汚染が進むと下記のような弊害が起きる。
まとめ
- 関数やブロックはスコープを持つ
- スコープはネストできる
- もっとも外側にはグローバルスコープがある
- スコープチェーンは内側から外側のスコープへと順番に変数が定義されているか探す仕組みのこと