JavaScript | 基礎構文:スコープ・実行コンテキスト – 変数のシャドーイング

JavaScript JavaScript
スポンサーリンク

変数のシャドーイングとは何か

変数のシャドーイングとは、外側のスコープにある変数と同じ名前の変数が内側のスコープで宣言されたとき、内側の変数が外側の変数を「隠す」現象のことです。コードを実行すると、名前が同じでも「今いるスコープの変数」が優先され、外側の同名変数は見えなくなります。これはレキシカルスコープ(定義位置で見える範囲が決まる仕組み)の自然な挙動です。

ここが重要です:

  • 「内側が優先される」というルールにより、意図せず外側の値が使われないことがあります。変数名のつけ方とスコープの意識が、バグを避ける鍵になります。

なぜシャドーイングが起こるのか(深掘り)

JavaScript は変数を探すとき、今いるスコープから外側へ段階的に探索します(スコープチェーン)。同じ名前が内側にあれば、外側の探索に進む前に見つかった内側の変数で確定します。つまり「近いほうが勝つ」。このため、外側の変数は存在していても、内側で同名を宣言すると内側が使われます。

  • 実務では「同じ名前を別スコープで使う」こと自体は普通ですが、意味が紛れると可読性が落ちます。意図をはっきりさせるために、内外で役割の異なる変数に同じ名前を付けない工夫が重要です。

基本例で理解する

例題1:内側が外側を隠す

const name = "太郎"; // 外側

function greet() {
  const name = "花子"; // 内側(シャドーイング)
  console.log(`こんにちは、${name}`); // 花子
}

greet();
console.log(name); // 太郎(外側はそのまま)
JavaScript

関数内では「近いほう」の name が優先され、外側の name は見えません。


例題2:ブロックスコープでのシャドーイング

let total = 100; // 外側

if (true) {
  let total = 5; // ブロック内でシャドーイング
  console.log(total); // 5
}

console.log(total); // 100
JavaScript

let/const はブロックスコープを持つため、{} 内の同名が外側を隠します。


例題3:関数引数もシャドーイングする

const rate = 0.1;

function calc(price, rate) { // 引数 rate が外側の rate を隠す
  return Math.floor(price * (1 + rate));
}

console.log(calc(1000, 0.08)); // 1080
JavaScript

引数名が外側の変数名と同じだと、引数が優先されます。引数は「関数の最も近いスコープ」にあるためです。


var と let/const の違いが生む影響(注意点を深掘り)

var は関数スコープ、let/const はブロックスコープです。どこに「内側のスコープ」が生まれるかが違うため、シャドーイングの起こり方にも差が出ます。

var x = 1;
if (true) {
  var x = 2; // ブロックでは新しいスコープができない(上書き)
}
console.log(x); // 2(隠すのではなく同じスコープで再宣言)

let y = 1;
if (true) {
  let y = 2; // ブロックスコープでシャドーイング
  console.log(y); // 2(内側が優先)
}
console.log(y); // 1(外側は保たれる)
JavaScript

ここが重要です:

  • var は「隠す」ではなく「同じスコープに再宣言されて上書き」になりがちで、予期せぬ影響を広げます。シャドーイングのコントロール性を高めるためにも、基本は let/const を使いましょう。

シャドーイングによる落とし穴(深掘り)

誤った上書きと読み違い

内側の変数が外側を隠しているのに、外側が使われる前提でコードを書くと誤動作します。読み手も「どの値が参照されるか」を取り違えやすいので、名前を変えるかスコープを分けることで意図を明確にするべきです。

let config = { mode: "prod" };

function setup() {
  let config = { mode: "dev" }; // シャドーイング
  // ここでの config は dev、外の config とは別物
}
JavaScript

デバッグの難しさ

ログに同じ名前を出しても、スコープで指している実体が違うため、原因追跡が難しくなります。デバッグ時は「どのスコープの変数か」を必ず確認しましょう。


シャドーイングをうまく使うコツ

  • 内側で短命の補助変数を使うときだけ、外側と同名を許容する。処理のまとまりが明確なら読みやすさが保てます。
  • 役割が異なるなら名前を変える(例:外側 user, 内側 currentUser)。
  • let/const を使い、ブロックスコープで安全に閉じ込める。var は上書きの危険があるため避ける。
  • 関数引数名は外側の重要な変数名と衝突させない。引数が優先されることを常に意識する。

まとめ

変数のシャドーイングは、内側スコープの同名変数が外側を「隠す」ことで起こります。レキシカルスコープの探索順(内→外)により、近いほうが優先されます。let/const では安全にブロックスコープで隠せますが、var は同じスコープで再宣言されやすく、思わぬ上書きを招きます。名前の設計とスコープの意識を徹底すれば、読みやすく安全なコードを保てます。

タイトルとURLをコピーしました