Code Fix

上級

プライベートフィールド外部アクセスの構文エラー原因

#で始まるプライベートフィールドを、宣言したクラスの外からドットで直接読み書きしようとしたときに出るエラーです。他のエラーと違い、実行前の構文解析の段階で検出されます。

エラーメッセージの読み方

main.js:6
main.js
ファイル名
6
行番号 — Node.jsが構文解析を諦めた位置
SyntaxError
エラークラス — 実行前の構文チェックで検出されました
Private field '#balance' must be declared in an enclosing class
内容 — 期待していたもの、または受け付けられなかったもの

このエラーが出る典型パターン

パターン1

 1  class Account {
 2    #balance = 100;
 3    getBalance() { return this.#balance; }
 4  }
 5  const acc = new Account();
 6  console.log(acc.#balance    );
                        ^
main.js:6 console.log(acc.#balance); ^ SyntaxError: Private field '#balance' must be declared in an enclosing class

プライベートフィールドはクラスの外から直接アクセスできません。値を取得したい場合はgetBalance()のような公開メソッド経由にします。

直し方: acc.#balance を acc.getBalance() にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  class Wallet {
 2    #balance = 500;
 3    deposit(amount) { this.#balance += amount; }
 4    getBalance() { return this.#balance; }
 5  }
 6  const w = new Wallet();
 7  w.deposit(100);
 8  console.log(w.#balance    );
                       ^
main.js:8 console.log(w.#balance); ^ SyntaxError: Private field '#balance' must be declared in an enclosing class

#balanceは宣言したクラスの中でしか読み書きできません。外部への公開はメソッドを介して行います。

直し方: w.#balance を w.getBalance() にします。

この問題を解いてみる →

パターン3

 1  class Timer {
 2    #seconds = 0;
 3    tick() { this.#seconds++; }
 4    getSeconds() { return this.#seconds; }
 5  }
 6  const t = new Timer();
 7  t.tick();
 8  t.tick();
 9  console.log(t.#seconds    );
                       ^
main.js:9 console.log(t.#seconds); ^ SyntaxError: Private field '#seconds' must be declared in an enclosing class

#secondsを外から直接読もうとすると実行前の構文チェックで弾かれます。公開したい値はgetSeconds()のようなメソッドで返します。

直し方: t.#seconds を t.getSeconds() にします。

この問題を解いてみる →

パターン4

 1  class Vault {
 2    #code = "1234";
 3    verify(input) { return input === this.#code; }
 4  }
 5  const v = new Vault();
 6  console.log(v.#code         );
                        ^
main.js:6 console.log(v.#code); ^ SyntaxError: Private field '#code' must be declared in an enclosing class

プライベートフィールドはクラスの外から直接アクセスできません。公開メソッド経由で確認する必要があります。

直し方: v.#code を v.verify("1234") にします。

この問題を解いてみる →

パターン5

 1  class Score {
 2    #points = 0;
 3    add(n) { this.#points += n; }
 4    getPoints() { return this.#points; }
 5  }
 6  const s = new Score();
 7  s.add(5);
 8  console.log(s.#points    );
                      ^
main.js:8 console.log(s.#points); ^ SyntaxError: Private field '#points' must be declared in an enclosing class

#pointsは宣言したクラスの中でしか読み書きできません。外部への公開はgetPoints()のようなメソッドで行います。

直し方: s.#points を s.getPoints() にします。

この問題を解いてみる →

よくある誤解

プライベートフィールドへのアクセス制限は、実行時にチェックされる通常のエラー(TypeErrorなど)だと思われがちですが、実際には構文としてその場に存在してはいけないものとして扱われ、SyntaxErrorになります。クラスの外に公開したい値は、getterやメソッド経由で提供する必要があります。

実務での勘所

以前のJavaScriptには本当の意味でのプライベートは無く、_fieldのようにアンダースコアを先頭に付けて「触らないでください」という合図を送るだけの、強制力の無い命名規約に頼っていました。#で始まるプライベートフィールドは、TC39(仕様策定団体)が導入した本物の言語機能で、そのクラスの外では#という文字自体が構文として認識されないため、実行時のチェックではなく構文解析の段階で弾かれます。命名規約とは違い、外部から迂回してアクセスする方法が原理的に存在しません。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)