【実務・中級編】 変数シャドーイング(Variable Shadowing) – JavaScript実践ガイド

「なぜか値が取れない」を防ぐ。変数シャドーイングの正体と、現場で生き残るための作法

フロントエンド開発の現場で、「あれ、この変数の値、さっき定義したはずなのに書き換わってないぞ?」とデバッガを睨みつけた経験はないだろうか。

JavaScriptを触っていると一度は遭遇する「変数シャドーイング(Variable Shadowing)」。これは仕様上の挙動としては正しいものの、コードの可読性を著しく下げ、バグの温床になりやすい厄介な代物だ。

今日は、中級エンジニアの君たちに向けて、シャドーイングの裏側で何が起きているのか、そして「事故らないコード」を書くための思考プロセスを伝授しよう。

—

シャドーイングとは何か:内側のスコープによる「隠蔽」

シャドーイングとは、内側のスコープで外側のスコープと同じ名前の変数を再定義した際、内側の変数が外側の変数を一時的に見えなくする(覆い隠す)現象のことだ。

JavaScriptエンジンは、変数を参照する際、現在のスコープから始まって外側(上位スコープ)へと順に名前を探しにいく。最初に見つかった時点で探索を終了するため、内側に同じ名前があれば、外側の変数は「存在しないもの」として扱われる。

const userRole = ‘admin’; // 外側のスコープ

function printRole() {
const userRole = ‘guest’; // ここでシャドーイング発生!

// 内側のスコープでは ‘guest’ が参照される
console.log(`現在の役割: ${userRole}`);
}

printRole();
console.log(`外側の役割: ${userRole}`); // こちらは ‘admin’ のまま

この例は単純だが、コードが数千行規模になり、ブロック文(`if`や`for`)が入れ子になった瞬間に、この挙動は「予期せぬバグ」として牙を剥く。

—

なぜ「var」は危険なのか:巻き上げとの合わせ技

`var`を使っている現場は今すぐ撲滅すべきだが、歴史的経緯で残っているレガシーコードには注意が必要だ。`var`はブロックスコープを無視するため、シャドーイングがより意図しない形で発生する。

var status = ‘active’;

if (true) {
var status = ‘suspended’; // ブロックスコープを突き抜けて外側を上書きしてしまう
console.log(status); // ‘suspended’
}

console.log(status); // ‘suspended’ に書き換わっている!

`let`や`const`を使えばブロックスコープに閉じ込めることができるが、`var`は関数スコープしかないため、意図せず外側の変数を破壊してしまう。これが「`var`を使うな」と言われる最大の理由だ。

—

現場で実践すべき「シャドーイング事故」回避のベストプラクティス

現場でレビューをする際、私は以下の3点を徹底して守るように伝えている。

1. スコープを可能な限り小さく保つ

変数の寿命が長ければ長いほど、どこかで名前が衝突するリスクは増える。関数を細かく分割し、必要な場所で必要な変数を定義する。これが基本だ。

2. 名前付けの解像度を上げる

「`data`」や「`value`」のような汎用的な名前は、シャドーイングの最大の標的だ。

  • `const userData`
  • `const responseData`
  • `const inputValue`

このように、「何を指しているのか」を名前に含めるだけで、衝突のリスクは劇的に減る。

3. 静的解析(ESLint)に頼り切る

人間はミスをする。だからこそ、機械にルールを強制させるのがプロのやり方だ。ESLintの `no-shadow` ルールを有効にしておこう。

// .eslintrc.json の設定例
{
“rules”: {
“no-shadow”: [“error”, { “builtinGlobals”: false, “hoist”: “functions”, “allow”: [] }]
}
}

これをONにするだけで、意図しないシャドーイングをCIの段階で検知できる。

—

実務での一歩先行くヒント:ループ処理での事故

特に注意が必要なのが、`forEach`や`for…of`の中でのシャドーイングだ。

const items = [{ id: 1 }, { id: 2 }];

function processItems() {
const id = ‘GLOBAL_ID’; // 外側の変数

items.forEach((item) => {
// ここで item.id にアクセスすべきなのに、
// うっかり const id = item.id と書いてしまうと、
// 外側の id が隠蔽され、以降の処理でバグを引き起こす
const id = item.id;
console.log(`処理中: ${id}`);
});
}

こういうときは、「あえて名前を変える」勇気を持つこと。`itemId`や`currentId`など、一目で何の値か分かる名前にリネームするだけで、デバッグの時間は大幅に短縮される。

—

まとめ:変数は「名前」であり「責任」である

変数シャドーイングは、JavaScriptという言語の柔軟性ゆえの「副作用」だ。しかし、この挙動を理解し、適切に制御することは、君のコードの信頼性を確実に一段階引き上げる。

  • `var`は使わない。
  • 変数はなるべく短命にする。
  • 名前の衝突は、ツール(ESLint)と命名規則で防ぐ。

これらを守るだけで、君の書くコードはぐっと「プロフェッショナル」なものになるはずだ。明日からのコーディングで、ぜひ意識してみてほしい。何かあれば、いつでもコードを見せてくれ。現場からは以上だ。

コメント

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