クロピグログ

職業訓練で学んだことまとめ

【JavaScript授業十三日目】スコープ

●スコープとは

変数の参照範囲。

二種類ある(グローバルスコープ、ローカルスコープ)

ローカルスコープはさらに二種類ある(関数スコープ、ブロックスコープ[2015以降])

 

●変数宣言の種類(大きく分けて4種類)

宣言用キーワードなし
num1 = 100;

var
var num2 = 200;

let
let num3 = 300;

const
const NUM4 = 400;

 

・宣言用キーワードなし

グローバル変数として扱われる

 

・var

var num2 = 200;
var num2 = 2000OK
num2 = 20000; OK

宣言場所によってグローバル変数にもローカル変数にもなる

同名変数の宣言OK

うっかり違う値を管理する同名変数を上書きしてしまうリスクあり

 

・let

let num3 = 300;
let num3 = 3000; ←NG
num3 = 30000; OK

宣言場所によってグローバル変数にもローカル変数にもなる

同名変数の宣言NG

ブロックスコープをもつ

 

・const

const NUM4 = 400;
const NUM4 = 4000; ←NG
NUM4 = 40000; ←NG

定数の宣言:値の再代入ができない

読み取り専用変数

宣言場所によってグローバル変数にもローカル変数にもなる

同名変数の宣言NG

ブロックスコープをもつ

※変数名をすべて大文字にする(暗黙のルールで読み取り専用とわかりやすい[推奨])

 

●使い所迷ったら...

・一人で小さいもの作るときは「var」だけでOK

・複数人でプログラムする場合は「let」使うとバグは防げる

 

●関数内、関数外の例

・成功するパターン

●関数の定義
呼び出された時に関数ブロック内を実行
function test() {
  console.log('関数内:' + num);
  グローバル変数は関数内からも参照可能
}
 
var num = 100;
関数外で宣言された変数はグローバルスコープをもつ
グローバル変数として扱われる
console.log('関数外:' + num);
test(); 引数なし関数呼び出し

・失敗するパターン

●関数の定義
呼び出された時に関数ブロック内を実行
function test() {
 var num = 100;
 関数内で宣言された変数はローカルスコープ変数関数内でのみ使用可能
  console.log('関数内:' + num);
}
 
test(); 引数なし関数呼び出し
 
console.log('関数外:' + num);
関数外でローカル変数numを参照したが、変数numの使用範囲ではないので
定義していませんよとエラーになる

 

●グローバル・ローカルスコープに同名変数

function test() {
  var num = 200;
  console.log('関数内:' + num);
}
 
var num = 100;
test();関数呼出し  ←関数内:200
console.log('関数外:' + num);  ←関数外:100

グローバル変数numを参照

・この時点ではローカル変数は存在していない

 

関数内は「家」のイメージ

外の変数さんは見えるが、変数さんからは家の中は見えないイメージ

 

ブロックスコープ:let

・verの場合

if (true) {
  var num1 = 100;
 ブロック内で変数宣言
 varで宣言した場合はブロックスコープなし
  console.log('ブロック内:' + num1); ←ブロック内:100
}
console.log('ブロック外:' + num1); ←ブロック外:100
ブロックスコープなしなので、ブロック外でも使用可能

・letの場合

if (true) {
  let num2 = 200;
 ブロック内で変数宣言
 letで宣言した場合はブロックスコープあり
  console.log('ブロック内:' + num2); ←ブロック内:100
}
console.log('ブロック外:' + num2); ←エラー
ブロックスコープありなので、ブロック外では使用不可

 

●letは、スコープ内にnum2が宣言されていなければ同名変数を宣言可能

if (true) {
  let num2 = 200;
  console.log('ブロック内:' + num2);
}
let num2 = 300;
console.log('ブロック外:' + num2);

 

●こういうパターンもある

for (let i = 0i < 5i++) {
for文の()内で宣言した変数はforブロック内で宣言した変数と同義になる
  console.log(i);
}
console.log(i); ←エラー

・変数iはブロックスコープを持っているのでfor文外で使用できない

 

●先に宣言するときはスコープを意識する

・ダメな例

let time1 = 10;
if (time1 < 12) {
  let message1 = "おはよう"; ←このブロック内{ }だけの変数
else if (time1 < 18) {
  let message1 = "こんにちは"; ←このブロック内{ }だけの変数
else {
  let message1 = "こんばんは"; ←このブロック内{ }だけの変数
}
console.log(message1); ←エラー

・いい例

let time1 = 10;
let message1;
if (time1 < 12) {
  message1 = "おはよう";
else if (time1 < 18) {
  message1 = "こんにちは";
else {
  message1 = "こんばんは";
}
console.log(message1); ←おはよう

 

●letは巻き上げ(ホイスティング)対象から外れる

console.log(num99); ←undefined(ホイスティングされているから)
var num99 = 100;
 
console.log(num98); ←エラー
let num98 = 100;
letで宣言された変数は巻き上げ(ホイスティング)対象から外れる

 

 

●定数:const

const NUM = 100;
 
console.log(NUM); ←100
NUM = 200;
console.log(NUM); ←エラー

・constで宣言すると定数
・初回のみ代入可能で2回目以降の代入は不可
・暗黙のルール:変数名はすべて大文字
・値の変更がない場合はすべて定数が望ましい

 

●未宣言変数

function test() {
  num = 100;
 キーワードなしの変数はグローバル変数として作成される
 本来の姿→ window.num = 100; (window.が省略されたもの)
  console.log('関数内:' + num); ←関数内:100
}
 
test();
console.log('関数外:' + num); ←関数外:100

・関数外に変数numの宣言がないのに利用できる

・関数内の未宣言変数の記述があるため

・なるべく未宣言変数は使わない

・特に関数内で未宣言変数を使うのはやめる!