JavaScriptのスコープ:変数や定数が使える範囲

関数の引数と戻り値を学んだ後、「スコープ」を学びました。スコープは、定数や変数を使用できる範囲のことです。これを理解することで、予期しないバグを防げます。

スコープとは

スコープは、定数や変数を使用できる範囲のことです。どこで定義したかによって、使える場所が変わります。

const message = "こんにちは";  // どこで使える?

const greet = () => {
  const name = "太郎";  // どこで使える?
};

定数や変数には、それぞれ「使える範囲」があります。

グローバルスコープ:関数の外側で定義

関数の外側で定義された定数や変数は、プログラムのどこでも利用できます。これを「グローバルスコープ」と言います。

const message = "こんにちは";  // グローバルスコープ

const greet = () => {
  console.log(message);  // 関数内から使える
};

greet();  // こんにちは
console.log(message);  // こんにちは(関数外からも使える)

グローバルスコープの変数や定数は、プログラム全体で共有されるため、どこからでもアクセスできます。

ローカルスコープ:関数の内側で定義

関数内で定義された定数や変数は、その関数の内側でのみ使用できます。これを「ローカルスコープ」と言います。

const greet = () => {
  const name = "太郎";  // ローカルスコープ
  console.log(name);
};

greet();  // 太郎

// ❌ エラー:関数の外側からは使えない
console.log(name);  // ReferenceError: name is not defined

ローカルスコープの変数や定数は、その関数内でのみ有効です。関数の外からはアクセスできません。

スコープの視覚的イメージ

// グローバルスコープ(プログラム全体)
const globalMessage = "どこでも使える";

const functionA = () => {
  // functionAのローカルスコープ
  const localMessage = "functionA内でのみ使える";
  
  console.log(globalMessage);  // ✅ グローバルは使える
  console.log(localMessage);   // ✅ ローカルも使える
};

const functionB = () => {
  // functionBのローカルスコープ
  console.log(globalMessage);  // ✅ グローバルは使える
  console.log(localMessage);   // ❌ functionAのローカルは使えない
};

同じ名前の定数・変数を定義すると

関数の内側と外側で同じ名前の定数や変数を定義すると、別々のものとして処理されます。

const message = "グローバル";

const showMessage = () => {
  const message = "ローカル";  // グローバルのmessageとは別物
  console.log(message);
};

showMessage();  // ローカル(関数内のmessageが使われる)
console.log(message);  // グローバル(関数外のmessageが使われる)

関数内で同じ名前の定数を定義すると、関数内ではローカルの方が優先されます。

具体例:変数の独立性

let count = 10;  // グローバル

const increment = () => {
  let count = 0;  // ローカル(グローバルのcountとは別物)
  count += 1;
  console.log(`関数内: ${count}`);
};

increment();  // 関数内: 1
console.log(`関数外: ${count}`);  // 関数外: 10

グローバルの count とローカルの count は、名前が同じでも完全に別の変数として扱われます。

ブロックスコープ:{}で囲まれた範囲

if文for文switch文などの中括弧 {} で囲まれた部分にもスコープが適用されます。これを「ブロックスコープ」と言います。

if (true) {
  const message = "if文の中";
  console.log(message);  // if文の中
}

// ❌ エラー:if文の外からは使えない
console.log(message);  // ReferenceError: message is not defined

for文のブロックスコープ

for (let i = 0; i < 3; i++) {
  console.log(i);  // 0, 1, 2
}

// ❌ エラー:for文の外からは使えない
console.log(i);  // ReferenceError: i is not defined

letconst で定義した変数・定数は、ブロック内でのみ有効です。

スコープの重要性

1. 変数名の衝突を防ぐ

const calculateTax = (price) => {
  const rate = 0.1;  // この関数内でのみ有効
  return price * rate;
};

const calculateDiscount = (price) => {
  const rate = 0.2;  // 別のrate(衝突しない)
  return price * rate;
};

関数ごとにスコープが分かれているため、同じ名前の変数を別々の関数で使っても問題ありません。

2. 意図しない変更を防ぐ

let total = 0;  // グローバル

const addToTotal = (num) => {
  let total = num;  // ローカル(グローバルのtotalは変更されない)
  console.log(`関数内: ${total}`);
};

addToTotal(100);  // 関数内: 100
console.log(`グローバル: ${total}`);  // グローバル: 0(変更されていない)

ローカルスコープを使うことで、グローバル変数を意図せず変更してしまうリスクを減らせます。

var、let、constのスコープの違い

JavaScriptには、変数を定義する方法が3つあります。

宣言方法スコープ再代入
var関数スコープ可能
letブロックスコープ可能
constブロックスコープ不可

現代のJavaScriptでは letconst を使うことが推奨されます。

// ❌ varは避ける(ブロックスコープが効かない)
if (true) {
  var message = "varで定義";
}
console.log(message);  // varで定義(外から見える)

// ✅ let/constを使う(ブロックスコープが効く)
if (true) {
  const message = "constで定義";
}
console.log(message);  // エラー(外から見えない)

Pythonとの比較

Pythonにもスコープの概念があります。

# Python
message = "グローバル"

def greet():
    message = "ローカル"
    print(message)

greet()  # ローカル
print(message)  # グローバル
// JavaScript
const message = "グローバル";

const greet = () => {
  const message = "ローカル";
  console.log(message);
};

greet();  // ローカル
console.log(message);  // グローバル

基本的な考え方は同じですが、JavaScriptでは constlet を使うことで、よりきめ細かいスコープ管理ができます。

今日の学びのポイント

  • スコープ: 定数や変数を使用できる範囲
  • グローバルスコープ: 関数の外側(プログラム全体で使える)
  • ローカルスコープ: 関数の内側(その関数内でのみ使える)
  • 同じ名前の定数・変数は、内側と外側で別々のものとして扱われる
  • ブロックスコープ: {} で囲まれた範囲(if文、for文など)
  • 現代のJavaScriptでは letconst を使う

スコープを理解することで、バグを減らし、より安全なコードを書けるようになります。

コメント