JavaScriptにおけるスコープとは?
変数が「参照できるか」?を現す有効範囲のことです。
どこで変数を定義したかによって、どこからその変数を参照できるのかが決まります。
(関数の中? 関数の外? for文の中? if文の中?)
そして、スコープにより参照できる範囲が限定されることで、
変数名の競合を避け、無駄なメモリの消費を抑える役割があります。
目次:
関数スコープ
関数の中のスコープ(有効範囲)についてみていきたいと思います。
例: 関数の中のスコープ(有効範囲)について
collectという関数を定義します。
その中では、total = 10という数字を定義し、
それをconsole.logとして出力しています。
function collect(){
let total = 10;
console.log(total);
}
10
問: このconsole.logを{}波括弧の下に書いたら正しく出力されるのか?
function collect(){
let total = 10;
}
console.log(total);
出力結果
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3679750%2Fb2be3412-700f-e673-74f9-72ca9fbdee03.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=db49937554e03820e13b09a24797199b)
Errorが表示されてしまいました・・・
なぜでしょうか?
A.関数のスコープが影響しているからです。
このように、letやconstを使って変数を宣言した時、この変数は、その関数内にスコープ(参照できる範囲)が限定されるという性質を持ちます。
つまり、作成したcollect関数は、{}波括弧の中でしか使えず、関数の外では参照することができません。
なので、errorが表示されました。
関数のスコープの優先順位
また、関数のスコープには優先順位があります。
それぞれの例題をもとに、どの変数の値が優先されるのかをみていきましょう。
例1: 関数は関係のない出力結果
関数の外でlet宣言をし、関数の外で出力結果を出す場合。
let bird = "すずめ";
function birdWatch() {
let bird = "カラス"
}
console.log(bird);
出力結果は関数の外で定義した値(すずめ)が出力される。
(関数は定義しただけで、実行していないので当然出力結果に関数は関係ない。)
すずめ
例2: 関数スコープの出力結果
関数の外でlet宣言をし、関数の外で出力結果を出す場合。関数の定義を関数内で、実行を関数の外側で行う。
let bird = "すずめ";
function birdWatch() {
let bird = "カラス"
}
birdWatch();
console.log(bird);
出力結果は関数の外で定義した値(すずめ)が出力される。
(関数スコープの概念上、関数の中で定義した値を外側で参照することができないため。)
すずめ
例3: let変数宣言の上書き
関数の外でlet宣言をし、関数の中で同じ変数名を新たに宣言する。また、関数の中で出力結果を出す場合。関数の定義を関数内で、実行を関数の外側で行う。
let bird = "すずめ";
function birdWatch() {
let bird = "カラス"
console.log(bird);
}
birdWatch();
//console.log(bird);
出力結果は関数の中で定義した値(カラス)が出力される。
(関数スコープの概念上、関数の中で定義した値を外側で参照することができないため。外側のbirdWatchは実行されない。)
カラス
例4: スコープの拡張
関数の外でlet宣言をし、関数の中で出力結果を出す場合。関数の定義を関数内で、関数の実行を関数の外側で行う。
let bird = "すずめ";
function birdWatch() {
//let bird = "カラス"
console.log(bird);
}
birdWatch();
//console.log(bird);
出力結果は関数の外で定義した値(すずめ)が出力される。
すずめ
例3、例4の結果から分かる通り、関数の内側で同じ変数の宣言をした場合は、
関数の内側の変数が使用されるが、関数の内側の変数宣言がない場合、
外側の変数宣言が使用されます。
ブロックスコープ
{ と }(波括弧)で囲んだ範囲をブロックと呼び、(スコープ)参照範囲を限定します。
ブロック内で宣言された変数は、スコープ内でのみ参照でき、スコープの外側からは参照できません。
例1: ブロックスコープの外側のlet宣言
ブロックスコープの外でlet宣言をし、{}(波括弧)の中にif文、const宣言、let宣言をぞれぞれ記入。出力結果を{}(波括弧の)外側で行う。
let circle = 10;
if (circle > 5) {
const PI = 3.14
let msg = "綺麗な丸です。";
}
console.log(circle)
let宣言で宣言したcircleの値が出力される。
10
例2: ブロックスコープの内側のconst宣言
ブロックスコープの外でlet宣言をし、{}(波括弧)の中にif文、const宣言、let宣言をぞれぞれ記入。constの出力結果を{}(波括弧の)外側で行う。
let circle = 10;
if (circle > 5) {
const PI = 3.14
let msg = "綺麗な丸です。";
}
console.log(PI)
出力結果:
ブロックスコープの性質上、内側の値を参照できないため、Errorが出力されます。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3679750%2F74dead31-c37c-608b-a56c-804324bbfc88.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=b09323972548551c4e38c622d4e84d75)
例3: ブロックスコープの内側のlet宣言
ブロックスコープの外でlet宣言をし、{}(波括弧)の中にif文、const宣言、let宣言をぞれぞれ記入。letの出力結果を{}(波括弧の)外側で行う。
let circle = 10;
if (circle > 5) {
const PI = 3.14
let msg = "綺麗な丸です。";
}
console.log(msg)
出力結果:
ブロックスコープの性質上、内側の値を参照できないため、Errorが出力されます。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3679750%2F40fcadc6-f526-5636-d186-fccf429ba29e.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=ce3877f577891a20009e287666895c38)
2番, 3番の例に関しては、どちらもブロックスコープの性質上{}(波括弧)の内側の値を参照できないため、errorが出力されます。これは、ブロックスコープの性質です。
例4: if文だけではなく、for文もブロックスコープの対象。
for文を記入。letの出力結果を{}(波括弧の)外側で行う。
for (let i = 0; i < 5; i++) {
let msg = "iは5より小さいです。"
}
console.log(msg)
出力結果:
for文も、if文同様、{}(波括弧)内の文章はブロックスコープの対象となり、外側で中を参照することはできません。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F3679750%2Fc993a808-0cae-f2dc-c0cd-867d72c0d376.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=2b333f676b1a8a1135223b70f85721e1)
ブロックスコープの性質上、内側の値を参照できないため、Errorが出力されます。
まとめ:
スコープのまとめ:
・スコープとは、スコープは関数や{}(波括弧)などのアクセスする範囲を制限するものです。
・コードが変数にアクセスする際には、まずは内側から参照し、外側に参照先を広げていく性質を持ちます。