JavaScriptのスコープとは?var・let・constの違いを解説

JavaScriptのスコープの広がりと変数の違いを表現した抽象的なデジタルイメージ
JavaScriptのスコープとvar・let・constの違いを視覚的に表現したアイキャッチ画像

JavaScriptを学習するうえで欠かせない概念のひとつが「スコープ」です。
スコープを正しく理解していないと、意図しないバグや予期しない挙動につながることがあります。

本記事では、JavaScriptのスコープの基本から、varletconstの違いまでを、初心者でも確実に理解できるように解説します。

スコープとは何か

スコープとは、「変数や関数が有効になる範囲」のことです。

同じ名前の変数であっても、スコープが異なれば別のものとして扱われます。

スコープの基本イメージ

// scope-basic.js
const message = "グローバル";

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

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

この例では、同じ message という名前でも、関数内と外で別の値として扱われています。
これがスコープの基本的な考え方です。

スコープの種類

JavaScriptには主に以下の3つのスコープがあります。

  • グローバルスコープ
  • 関数スコープ
  • ブロックスコープ

それぞれ順番に見ていきます。

グローバルスコープ

特徴

  • どこからでもアクセスできる
  • スクリプト全体で共有される
// global-scope.js
const globalValue = "どこからでも使える";

function test() {
  console.log(globalValue);
}

test(); // どこからでも使える

グローバル変数は便利ですが、多用するとバグの原因になります。
予期せぬ上書きや競合が起きやすいため、必要最低限にすることが重要です。

関数スコープ

特徴

  • 関数内で宣言された変数は外からアクセスできない
  • varは関数スコープを持つ
// function-scope.js
function test() {
  var message = "関数内";
  console.log(message);
}

test(); // 関数内
console.log(message); // エラー

関数の外からはアクセスできないため、安全にデータを扱うことができます。

ブロックスコープ

特徴

  • {}(ブロック)単位で有効
  • letconstが対象
// block-scope.js
if (true) {
  let message = "ブロック内";
  console.log(message);
}

console.log(message); // エラー

ifforなどのブロック内で定義された変数は、外では使えません。

var・let・constの違い

スコープの理解とセットで重要なのが、変数宣言の違いです。

varの特徴

関数スコープを持つ

// var-scope.js
function test() {
  if (true) {
    var value = 10;
  }
  console.log(value); // 10
}

test();

varはブロックを無視して、関数全体で有効になります。

再宣言できる

// var-redeclare.js
var count = 1;
var count = 2;

console.log(count); // 2

同じ名前で再宣言できるため、バグの原因になりやすいです。

巻き上げ(ホイスティング)が発生する

// var-hoisting.js
console.log(value); // undefined
var value = 10;

宣言が先に処理されるため、エラーにならず undefined になります。

letの特徴

ブロックスコープを持つ

// let-scope.js
if (true) {
  let value = 10;
}

console.log(value); // エラー

ブロック外ではアクセスできません。

再宣言できない

// let-redeclare.js
let count = 1;
// let count = 2; // エラー

同じスコープ内での再宣言は禁止されています。

ホイスティングはされるが使えない(TDZ)

// let-tdz.js
// console.log(value); // エラー
let value = 10;

宣言前にアクセスするとエラーになります。
この期間を「TDZ(Temporal Dead Zone)」と呼びます。

constの特徴

ブロックスコープを持つ

// const-scope.js
if (true) {
  const value = 10;
}

console.log(value); // エラー

letと同様にブロックスコープです。

再代入できない

// const-reassign.js
const value = 10;
// value = 20; // エラー

一度代入した値は変更できません。

オブジェクトや配列は変更可能

// const-object.js
const user = { name: "Taro" };
user.name = "Jiro";

console.log(user.name); // Jiro

参照は固定ですが、中身の変更は可能です。

var・let・constの使い分け

実務では以下のルールが一般的です。

  • 基本は const
  • 再代入が必要な場合のみ let
  • varは基本的に使用しない

理由

  • 意図しない再代入を防げる
  • スコープが明確になる
  • バグを減らせる

よくあるバグと注意点

ループ内のvarによる問題

// var-loop.js
for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 100);
}

結果:

3
3
3

letで解決

// let-loop.js
for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 100);
}

結果:

0
1
2

スコープ理解に役立つ内部リンク

スコープの理解は、JavaScript全体の基礎理解につながります。

以下の記事もあわせて確認することで、より理解が深まります。

まとめ

JavaScriptのスコープは、変数の有効範囲を決める重要な仕組みです。

  • スコープには「グローバル・関数・ブロック」がある
  • varは関数スコープで扱いが難しい
  • letconstはブロックスコープで安全
  • 基本はconst、必要に応じてletを使う

スコープを正しく理解することで、予期しないバグを防ぎ、安定したコードを書くことができます。

関連記事