0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

レキシカルスコープ(Lexical Scope)とは — 備忘録

0
Last updated at Posted at 2026-05-31

定義

レキシカルスコープとは、変数のスコープがコードを書いた場所(定義した場所) によって決まる仕組みのこと。

関数が「どこで呼ばれたか」ではなく、「どこで定義されたか」によってスコープが決まる。

  • JavaScriptはレキシカルスコープ(静的スコープ)を採用している
  • 関数は定義時のスコープチェーンを保持する
  • これがクロージャの基盤になっている

コード例① 基本

外側の変数に内側からアクセスできる。

const name = 'Kengo';

function greet() {
  // name は外側のスコープで定義されているが参照できる
  console.log(`Hello, ${name}`);
}

greet(); // Hello, Kengo

コード例② 呼び出し場所は関係ない

定義時のスコープで変数が決まる(呼び出し場所ではない)。

const x = 'outer';

function showX() {
  console.log(x); // 定義時に outer スコープの x を参照
}

function callShowX() {
  const x = 'inner'; // 別の x を宣言しても影響しない
  showX();
}

callShowX(); // 'outer' → inner ではない

コード例③ クロージャとの関係

レキシカルスコープがあるからクロージャが成立する。

function makeCounter() {
  let count = 0;

  return function() {
    count++;
    // 返された関数は定義時のスコープ(count)を保持している
    console.log(count);
  };
}

const counter = makeCounter();
counter(); // 1
counter(); // 2

学習当初につまずいたこと

① 「定義した場所」と「呼び出した場所」の違いがわからなかった

最初は「関数を呼び出した場所の変数が使われる」と思い込んでいた。
下のコードで 'inner' が出力されると予想して、実際には 'outer' が出て混乱した。

const x = 'outer';

function showX() {
  console.log(x);
}

function callShowX() {
  const x = 'inner';
  showX(); // 'outer' が出る → 呼び出し場所の x ではなく、定義時の x
}

callShowX();

最初は「showX()callShowX の中に書いてあるから、callShowX のスコープが使われる」と読んでいた。

でも showX 自体はグローバルスコープで定義されている。callShowXshowX呼んでいるだけで、showX の定義場所とは別の話。

グローバルスコープ
  ├─ const x = 'outer'     ← showX が見ているのはここ
  ├─ function showX() {}   ← showX はここで定義されている
  └─ function callShowX() {
       const x = 'inner';  ← showX には関係ない
       showX();            ← 呼んでいるだけ
     }

腑に落ちたポイント:showX() という呼び出しが callShowX の中にあっても、showX の住所(定義場所)はグローバル」と考えたら整理できた。呼び出し場所ではなく、定義場所のスコープが使われる


② スコープチェーンのイメージがつかめなかった

「スコープが連鎖している」と言われてもピンとこなかった。
図で表すと理解しやすかった。

グローバルスコープ
  └─ 関数A のスコープ
        └─ 関数B のスコープ  ← ここから外側に向かって変数を探しに行く

変数を参照するとき、JSエンジンは内側から外側へ順番に探す。
見つかった時点で止まる。グローバルまで見つからなければ ReferenceError

腑に落ちたポイント: 「外側には出られるが、内側には入れない」と覚えた。


③ コードを読んでも変数がどこを参照しているか追えなかった

ネストが深くなると「この変数どこで定義されてる?」がわからなくなっていた。

const level = 'global';

function outer() {
  const level = 'outer';

  function inner() {
    const level = 'inner';
    console.log(level); // どの level? → 一番近い内側 = 'inner'
  }

  inner();
}

腑に落ちたポイント: 「使っている変数の宣言(const / let / var)を、内側から外側に向かって探す」という読み方を習慣にした。エディタの「定義へ移動」機能も活用した。


  • スコープはどこで定義したかで決まる(どこで呼んだかではない)
  • 内側のスコープから外側の変数には参照できる(逆はできない)
  • この仕組みのおかげでクロージャが使える
  • JSを読むとき「この変数はどこで定義された?」と考えると理解しやすい
0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?