---
type: errors
language: javascript
slug: cannot-access-before-initialization
title: "ReferenceError: Cannot access 'x' before initialization"
title_tag: "ReferenceError: Cannot access before initialization の直し方"
summary: >
  let / const / class を宣言より前で使うと出ます。var との違い、typeof でも避けられない理由、
  外側の同名変数を隠して起きる場合まで、原因ごとに直したコードを載せています。
description: >
  宣言はあるのに使えない状態（一時的死角）で出ます。var との違い、typeof でも避けられない理由、外側の同名変数を隠して起きる見つけにくい形まで、原因ごとに直し方を示します。
status: published
difficulty: 2
minutes: 8

versions:
  verified: "Node 22.22.3"
  since: "ES2015"
  deprecated: null
  removed: null

sources:
  - title: "Let and Const Declarations — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-let-and-const-declarations"
  - title: "ResolveBinding — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-resolvebinding"
  - title: "ReferenceError: can't access lexical declaration 'X' before initialization — MDN"
    url: "https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Errors/Cant_access_lexical_declaration_before_init"

terms: [一時的死角, 巻き上げ, ブロックスコープ]

links:
  related:
    - javascript/errors/assignment-to-constant-variable
    - javascript/errors/cannot-read-properties-of-undefined
    - javascript/errors/is-not-defined

content_updated_at: 2026-09-08
published_at: 2026-09-08
---

`let` / `const` / `class` を、**宣言より前で使った**ときに出ます。

```js bad
console.log(value);

let value = 1;
```
```output
ReferenceError: Cannot access 'value' before initialization
```

直し方は単純です。**宣言を、使うところより前に移します。**

```js run
let value = 1;

console.log(value);
```
```output
1
```

## なぜ「宣言していない」ではないのか

エラー文が `value is not defined` ではないことに注目してください。
**処理系は `value` の存在を知っています。** ただ、まだ[key:使える状態になっていない]だけです。

`let` と `const` は、ブロックの先頭から宣言の行までのあいだ、
[type:一時的死角（TDZ）]と呼ばれる状態に置かれます。
**名前はあるのに触れない区間**です。

`var` は違います。

```js run
console.log(typeof later);

var later = 1;
```
```output
undefined
```

`var` は宣言が先頭に[type:巻き上げ]られ、値は `undefined` で始まります。
だから**エラーにならずに `undefined` が出ます。**

| | 宣言より前で使うと |
|---|---|
| `var` | `undefined`（[bad:気づけない]） |
| `let` / `const` | **エラーになる** |
| `class` | **エラーになる** |
| 関数宣言 | 使える |

**エラーになるほうが安全です。** `var` は間違いを黙って通します。

## `typeof` でも避けられない

未宣言の変数なら `typeof` は安全ですが、[type:一時的死角]の中では違います。

```js run
console.log(typeof neverDeclared);

try {
  console.log(typeof later);
  let later = 1;
} catch (error) {
  console.log(error.name);
}
```
```output
undefined
ReferenceError
```

**`typeof` で存在を確かめる書き方は、ここでは効きません。**

## 原因1: 関数宣言と関数式を混同している

```js run
hoisted();

function hoisted() {
  console.log('関数宣言は先に使える');
}
```
```output
関数宣言は先に使える
```

`function` で書いた関数は、**丸ごと巻き上げられる**ので先に呼べます。
ところが `const` に入れた関数は呼べません。

```js bad
notYet();

const notYet = () => {};
```
```output
ReferenceError: Cannot access 'notYet' before initialization
```

**同じ「関数」でも書き方で挙動が違います。**
アロー関数や関数式を使うなら、**定義を呼び出しより上に置いてください。**

## 原因2: クラスを定義より前で使う

```js bad
new Thing();

class Thing {}
```
```output
ReferenceError: Cannot access 'Thing' before initialization
```

`class` も `let` と同じ扱いです。**巻き上がりません。**

## 原因3: 外側の同じ名前を隠している

**これがいちばん見つけにくい形です。**

```js bad
const name = '外側';

function show() {
  console.log(name);

  const name = '内側';
}

show();
```
```output
ReferenceError: Cannot access 'name' before initialization
```

`console.log(name)` は[bad:外側の `name` を見ていません]。
関数の中に `const name` があるので、**その関数の中では最初から内側の `name`** です。
そしてその時点では、まだ触れません。

外側を使いたいなら、**内側の宣言の名前を変えてください。**

```js run
const name = '外側';

function show() {
  console.log(name);

  const inner = '内側';

  console.log(inner);
}

show();
```
```output
外側
内側
```

ブロックの中でも同じことが起きます。

```js run
let n = 1;

{
  try {
    console.log(n);
    let n = 2;
  } catch (error) {
    console.log(error.name);
  }
}

console.log(n);
```
```output
ReferenceError
1
```

## 似ているエラーとの違い

| 文言 | 意味 |
|---|---|
| `Cannot access 'x' before initialization` | **宣言はある。まだ使えない** |
| `x is not defined` | そもそも宣言が無い（綴り違い・読み込み忘れ） |
| `Identifier 'x' has already been declared` | 同じ名前を[num:2]回宣言した |
| `Assignment to constant variable.` | `const` に代入した → [別ページ](/ja/javascript/errors/assignment-to-constant-variable/) |

```js run
try {
  eval('let dup = 1; let dup = 2;');
} catch (error) {
  console.log(error.name + ': ' + error.message);
}
```
```output
SyntaxError: Identifier 'dup' has already been declared
```

[dim:このページの実行結果は Node 22.22.3 のものです。文言は処理系と版によって変わります。自分の環境で出た文言で検索してください。]

## 探しかたの順序

1. エラーの文に出ている**名前**を控える
2. その名前の宣言を、**同じ関数・同じブロックの中**で探す
3. 見つかったら、**使っている行より下にないか**見る
   - 下にある → 宣言を上へ移す
   - 外側の同名を使いたかった → **内側の名前を変える**
4. 見つからなければ、`var` を `let` に変えた直後ではないか疑う

## まとめ

- 宣言はある。**まだ使える状態になっていない**（[type:一時的死角]）
- `var` は `undefined` になるだけ。[em:エラーになるほうが安全]
- **`typeof` でも避けられない**
- 関数宣言は巻き上がるが、`const` に入れた関数は巻き上がらない
- `class` も巻き上がらない
- **外側の同名を隠している場合がいちばん見つけにくい**

`'use strict'` を書くと何が変わるかは、文字列の第1回でも**同じコードを両方のモードで実行して**比べています。
→ [文字列の基本](/ja/javascript/learn/string/basics/)
