YovStudio

article 読むトレ #04:広すぎる守備範囲

公開日: 2025-06-21著者: Yov in YovStudio

今回のお題コード

AI 「数字を合計して表示する処理ができました!なかなかの出来映えでしょ?」

let total = 0;

function sum(items) {
  for (let i = 0; i < items.length; i++) {
    total += items[i];
  }
}

sum([1, 2, 3]);
console.log(total);

どう動く?

さっそく読んでみましょう。

以下のようなサイトで動かしてみてもよいです。

気になるポイント

このコード、問題なく動きます。 実行結果は以下の通りで、しっかり 1 + 2 + 3 の結果が出力されています。

6

さてこのコード、どこか違和感を覚えませんでしたか?

私は total のスコープが必要以上に広い点が気になりました。
total にコード上のどこからでもアクセスできるため、値がどこで変わっているのか追いづらく、他の関数が増えたりして長くなってくると、total が他の処理で誤って更新されるリスクが生じます。

いきなりスコープとか言われても…という方もいるかと思うので、ちょっとたとえ話をしてみましょうか。

たとえばサッカーで、ゴールキーパーがフィールドを自由に走り回っていたら?
どこで何をしているか分からないし、肝心な時にゴール前にいないかもしれない。
守るべき範囲(=スコープ)は明確に、なるべく狭く。
変数のスコープも同じなんです。
とはいえ実際のゴールキーパーは状況に応じて前に出たりもしますが…ここでは「守るべき範囲をあらかじめ決めておくことが大切だよね」というイメージで捉えてもらえればと思います。

そして話を戻しますが、この total がどこからでもアクセスできるのをいいことに、誰かが別の場所に total = -1 というコードを追加してしまったら?
sum() が正しく動いたのに -1 が表示される」なんてことが起こり、そうすると sum() を疑うべきか他の処理を疑うべきか、ひと目で判断しづらくなってしまうのです。
最悪、ソース全体から total の使用箇所を洗い出すハメになります。そんなこと、避けたいですよね。

誤って total を書き換えてしまった例

スコープが広すぎると別の処理が思わぬ形で変数を書き換えてしまうという状況をイメージしやすくするため、例を載せておきます。
いまは短いコードだから問題が見えにくいですが、実務では関数やファイルが増えていくため、こうした「どこでもアクセスできる変数」はトラブルの温床になります。

let total = 0;

function sum(items) {
  for (let i = 0; i < items.length; i++) {
    total += items[i];
  }
}

// 誰かが画面の表示を初期化する関数を追加
function resetUI() {
  // 画面(UI) を初期化するつもりが…
  console.log('Resetting UI...');
  total = -1; // 誤って total を変えちゃってる!?
}

sum([1, 2, 3]);
resetUI(); // sum() のあとに画面(UI)をリセットしたかっただけなのに…
console.log(total);

どう修正する?

変数は可能な限りスコープを狭めて、影響範囲を限定させるのが鉄則です。 今回は totalsum() の中でしか使えなくして、sum() には処理結果をリターンさせるのがよいでしょう。
このリターンを const で取得して表示するようにすれば、結果を意図せず変えてしまう、というリスクもなくせます。

function sum(items) {
  let total = 0; // 関数内スコープ

  for (let i = 0; i < items.length; i++) {
    total += items[i];
  }

  return total;
}

const result = sum([1, 2, 3]);
console.log(result);

「変数名が total ではなく result になってるけどなんで!?」と思った方、これには理由があります。
sum() の中でも total を使っているので、外でも同じ名前にしてしまうと「この total はどっち?」と読み手が混乱しやすくなります。 そこで外側では result にして、「これは最終結果で、もう変えませんよ」という意味も込めました。

補足: letconst どちらを使う?

どの言語でも基本的に、意図してない誤操作を防ぐことを第一に考えます。
JavaScript なら const であれば値を変更できない(※)ので、可能な限り const を使用します。
どうしても途中で値を変える必要がある場合だけ let を使用するようにしましょう。

※ 厳密には「再代入できない」という意味で、オブジェクトの中身などは変えられます。

JavaScript には他にも var がありますが、これは少々特殊なので今回は説明を省略します。

補足:スコープってなに?

スコープは、変数や関数などがどこから参照・利用できるかを決める「有効範囲」のことです。
必要以上にスコープを広げないことを心がけると、コードの安全性と読みやすさが向上します。

以下のスコープは、今のうちから特に意識してほしいものです。

  • ブロックスコープ: if 文や for 文など {} の中だけで有効
  • 関数スコープ:関数の中だけで有効
  • クラススコープ:クラスの中だけで有効(Java など)
  • グローバルスコープ:プログラム全体で有効

今回の読みどころ

  • 変数のスコープは必要最小限に狭くするのが読みやすさのコツ
  • スコープが広いと影響範囲が大きくなり、読み手は「変数がどこで使われるか」を常に考えなければならない
  • スコープを意識することで「この変数が使える範囲はここまで」と自然に把握できるようになり、理解が早くなる