1. 開発者向けのウェブ技術
  2. JavaScript
  3. JavaScript リファレンス
  4. クラス
  5. プライベート要素

このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。

View in English Always switch to English

プライベート要素

プライベート要素は、パブリックである通常のクラスプロパティ、例えばクラスフィールドやクラスメソッドなどに対するものです。プライベート要素はハッシュ # 接頭辞を使用して作成され、クラスの外部から合法的に参照することはできません。これらのクラスプロパティのプライバシーカプセル化は JavaScript 自身によって強制されます。プライベート要素にアクセスするには、ドット記法を使用するしかなく、また、そのアクセスはプライベート要素を定義するクラス内でのみ可能です。

プライベート要素は、この構文が存在する以前はネイティブではありませんでした。プロトタイプ継承では、 WeakMap オブジェクトやクロージャでその振る舞いをエミュレートすることができますが、使いやすさの面からは # 構文にはかないません。

メモ: MDN では、「プライベートプロパティ」という用語の使用は避けています。JavaScript のプロパティには文字列またはシンボルのキーがあり、writableenumerableconfigurable などの属性がありますが、プライベート要素にはこれらの属性は存在しません。プライベート要素は、おなじみのドット表記でアクセスできますが、プロキシーを行ったり、列挙したり、削除したり、 Object メソッドを使用して対話したりすることはできません。

構文

js
class ClassWithPrivate {
 #privateField;
 #privateFieldWithInitializer = 42;
 #privateMethod() {
 // ...
 }
 static #privateStaticField;
 static #privateStaticFieldWithInitializer = 42;
 static #privateStaticMethod() {
 // ...
 }
}

さらにいくつかの構文上の制約があります。

  • クラス内で宣言するプライベート識別子はすべて固有のものである必要があります。名前空間は、静的プロパティとインスタンスプロパティの間で共有されます。唯一の例外は、 2 つの宣言がゲッターとセッターのペアを定義している場合です。
  • プライベート識別子は #constructor にすることができません。

解説

ほとんどのクラスプロパティには、プライベートの対応するものがあります。

  • プライベートフィールド
  • プライベートメソッド
  • プライベート静的フィールド
  • プライベート静的メソッド
  • プライベートゲッター
  • プライベートセッター
  • プライベート静的ゲッター
  • プライベート静的セッター

これらの機能をまとめてプライベート要素と呼びます。しかし、JavaScript でコンストラクターをプライベートにすることはできません。クラスの外部でクラスが構築されないようにするには、プライベートフラグを使用する必要があります。

プライベート要素は # 名前(「ハッシュ-名前」と読みます)で宣言され、接頭辞として # が付けられます。ハッシュ接頭辞はプロパティ名の一部です。古いアンダースコア接頭辞規約 _privateField との関係を思い描いてください。しかし、普通の文字列プロパティではないので、ブラケット記法を使って動的にアクセスすることはできません。

クラス外から # 付きの名を参照すると構文エラーになります。また、呼び出される前に宣言されていないプライベート要素を参照したり、宣言されている要素を delete で削除しようとしても構文エラーになります。

js
class ClassWithPrivateField {
 #privateField;
 constructor() {
 delete this.#privateField; // Syntax error
 this.#undeclaredField = 42; // Syntax error
 }
}
const instance = new ClassWithPrivateField();
instance.#privateField; // Syntax error

JavaScript は動的言語ですが、ハッシュ識別子の構文が特殊であり、構文レベルで通常のプロパティとは異なるため、このコンパイル時チェックを行うことができます。

メモ: Chrome コンソールで実行するコードは、クラス外からプライベート要素にアクセスすることができます。これは JavaScript の構文制限を開発者ツール限定で緩和したものです。

あるプライベート要素を持っていないオブジェクトからその要素にアクセスすると、通常のプロパティのように undefined を返すのではなく、TypeError が発生します。

js
class C {
 #x;
 static getX(obj) {
 return obj.#x;
 }
}
console.log(C.getX(new C())); // undefined
console.log(C.getX({})); // TypeError: Cannot read private member #x from an object whose class did not declare it

この例では、静的関数の中や、外部で定義したクラスのインスタンスでもプライベート要素にアクセスできることも示しています。

in 演算子を使用すると、外部で定義されたオブジェクトがそのプライベート要素を持っているかどうかを調べることができます。そのプライベートフィールドまたはメソッドが存在する場合、true が返され、それ以外の場合は false が返されます。

js
class C {
 #x;
 constructor(x) {
 this.#x = x;
 }
 static getX(obj) {
 if (#x in obj) return obj.#x;
 return "obj must be an instance of C";
 }
}
console.log(C.getX(new C("foo"))); // "foo"
console.log(C.getX(new C(0.196))); // 0.196
console.log(C.getX(new C(new Date()))); // the current date and time
console.log(C.getX({})); // "obj must be an instance of C"

オブジェクトが現在のクラスのプライベート要素を 1 つでも持っていることが見つかった場合(try...catch または in チェックのいずれか)、他にもプライベート要素をすべて持っている必要があります。あるクラスのプライベート要素を持つオブジェクトは、一般的にそのクラスによって構築されたことを意味しています(常にではありません)。

プライベート要素は、現在のクラス本体内でのみアクセスすることができ、サブクラスには継承されないため、プロトタイプ継承モデルにはありません。クラスが異なると、プライベート要素は同じ名前でも全く異なるものであり、相互運用はできません。クラスごとに管理される、インスタンスに付加された外部メタデータとして考えてください。このため、 structuredClone() はプライベート要素を複製せず、 Object.freeze()Object.seal() は、プライベート要素には影響しません。

プライベートフィールドがいつ、どのように初期化されるかについての詳細は、プライベートクラスフィールドを参照してください。

プライベートフィールド

プライベートフィールドには、プライベートインスタンスフィールドとプライベート静的フィールドがあります。プライベートフィールドは、クラス宣言の内部からのみアクセスすることができます。

プライベートインスタンスフィールド

プライベートインスタンスフィールドは、パブリック版と次の点で似ています。

  • 基底クラスでコンストラクターが実行される前か、サブクラスで super() を呼び出した直後に追加されます。
  • そのクラスのインスタンスでのみ利用できます。
js
class ClassWithPrivateField {
 #privateField;
 constructor() {
 this.#privateField = 42;
 }
}
class Subclass extends ClassWithPrivateField {
 #subPrivateField;
 constructor() {
 super();
 this.#subPrivateField = 23;
 }
}
new Subclass(); // 開発者ツールでは Subclass {#privateField: 42, #subPrivateField: 23} と表示

メモ: 基底クラス ClassWithPrivateField#privateFieldClassWithPrivateField のプライベートメンバーであり、派生クラス Subclass からはアクセスできません。

オーバーライドしたオブジェクトの返却

クラスのコンストラクターは異なるオブジェクトを返すことができ、そのオブジェクトは派生クラスのコンストラクターの新しい this として使用することができます。派生クラスは、返されたオブジェクトにおいてプライベートフィールドを定義することができます。つまり、無関係なオブジェクトにプライベートフィールドを「刻印」することが可能です。

js
class Stamper extends class {
 // コンストラクターが指定されたオブジェクトを返す基底クラス
 constructor(obj) {
 return obj;
 }
} {
 // この宣言は、基底クラスのコンストラクターが返すオブジェクトに
 // プライベートフィールドを「刻印」する
 #stamp = 42;
 static getStamp(obj) {
 return obj.#stamp;
 }
}
const obj = {};
new Stamper(obj);
// `Stamper` は `Base` を呼び出して `obj` を返す。次に
// `Stamper` は `obj` に `#stamp` を定義する
console.log(obj); // 一部の開発者ツールでは {#stamp: 42} と表示
console.log(Stamper.getStamp(obj)); // 42
console.log(obj instanceof Stamper); // false
// プライベート要素に 2 度刻印することはできません。
new Stamper(obj); // Error: Initializing an object twice is an error with private fields

警告: これはとても混乱を招きかねないことです。一般的に、コンストラクターから任意のものを返すのは避けるようにしましょう。特に this に関係のないものを返すのは避けるようにしましょう。

プライベート静的フィールド

プライベート静的フィールドは、パブリック版と次の点で似ています。

  • クラスが評価される際にクラスのコンストラクターに追加されます。
  • クラス自身からのみ利用できます。
js
class ClassWithPrivateStaticField {
 static #privateStaticField = 42;
 static publicStaticMethod() {
 return ClassWithPrivateStaticField.#privateStaticField;
 }
}
console.log(ClassWithPrivateStaticField.publicStaticMethod()); // 42

プライベート静的フィールドには制限があります。プライベート静的フィールドを定義したクラスのみが、そのフィールドにアクセスできます。 this を使用すると、予期しない動作をする可能性があります。次の例では、 SubClass.basePublicStaticMethod() を呼び出そうとしたときに thisSubclass クラスを(BaseClassWithPrivateStaticField クラスではなく)参照してしまい、 TypeError が発生します。

js
class ClassWithPrivateStaticField {
 static #privateStaticField = 42;
 static publicStaticMethod() {
 return this.#privateStaticField;
 }
}
class Subclass extends ClassWithPrivateStaticField {}
Subclass.publicStaticMethod(); // TypeError: Cannot read private member #privateStaticField from an object whose class did not declare it

これは、そのメソッドに super を付けて呼び出すのと同じです。 super のメソッドはスーパークラスを this として呼び出すわけではないからです。

js
class ClassWithPrivateStaticField {
 static #privateStaticField = 42;
 static publicStaticMethod() {
 // super を呼び出しても、 `this` は Subclass を参照している
 return this.#privateStaticField;
 }
}
class Subclass extends ClassWithPrivateStaticField {
 static callSuperMethod() {
 return super.publicStaticMethod();
 }
}
Subclass.callSuperMethod(); // TypeError: Cannot read private member #privateStaticField from an object whose class did not declare it

プライベート静的フィールドには常に this ではなく、クラス名でアクセスするようにしてください。

プライベートメソッド

プライベートメソッドには、プライベートインスタンスメソッドとプライベート静的メソッドがあります。プライベートメソッドは、クラス宣言の内部からのみアクセスすることができます。

プライベートインスタンスメソッド

プライベートインスタンスメソッドは、パブリック版と次の点で異なります。

  • インスタンスフィールドが導入される前に、直ちに導入されます。
  • クラスのインスタンスでのみ利用可能であり、 .prototype プロパティでは利用できません。
js
class ClassWithPrivateMethod {
 #privateMethod() {
 return 42;
 }
 publicMethod() {
 return this.#privateMethod();
 }
}
const instance = new ClassWithPrivateMethod();
console.log(instance.publicMethod()); // 42

プライベートインスタンスメソッドは、ジェネレーター、非同期、非同期ジェネレーターの関数にすることができます。プライベートゲッターとセッターも可能で、パブリックのゲッターセッターと同じ構文に従います。

js
class ClassWithPrivateAccessor {
 #message;
 get #decoratedMessage() {
 return `🎬${this.#message}🛑`;
 }
 set #decoratedMessage(msg) {
 this.#message = msg;
 }
 constructor() {
 this.#decoratedMessage = "hello world";
 console.log(this.#decoratedMessage);
 }
}
new ClassWithPrivateAccessor(); // 🎬hello world🛑

パブリックメソッドと異なり、プライベートメソッドはクラスの .prototype プロパティからアクセスすることはできません。

js
class C {
 #method() {}
 static getMethod(x) {
 return x.#method;
 }
}
console.log(C.getMethod(new C())); // [Function: #method]
console.log(C.getMethod(C.prototype)); // TypeError: Receiver must be an instance of class C

プライベート静的メソッド

プライベート静的メソッドは、パブリック版と次の点で似ています。

  • クラスの評価時点でクラスのコンストラクターに追加されます。
  • クラス自身からのみ利用できます。
js
class ClassWithPrivateStaticMethod {
 static #privateStaticMethod() {
 return 42;
 }
 static publicStaticMethod() {
 return ClassWithPrivateStaticMethod.#privateStaticMethod();
 }
}
console.log(ClassWithPrivateStaticMethod.publicStaticMethod()); // 42

プライベート静的メソッドは、ジェネレーター関数、非同期関数、非同期ジェネレーター関数、などがあります。

前述のプライベート静的フィールドの制限は、プライベート静的メソッドにも当てはまり、this を同様に使用すると予期しない動作が発生する可能性があります。次の例では、 Derived.publicStaticMethod2() を呼び出そうとすると、これは Base クラスではなく Derived クラスを参照するため、TypeError が発生します。

js
class ClassWithPrivateStaticMethod {
 static #privateStaticMethod() {
 return 42;
 }
 static publicStaticMethod() {
 return this.#privateStaticMethod();
 }
}
class Subclass extends ClassWithPrivateStaticMethod {}
console.log(Subclass.publicStaticMethod()); // TypeError: Cannot read private member #privateStaticMethod from an object whose class did not declare it

プライベートコンストラクターをシミュレーション

他の多くの言語では、コンストラクターをプライベートとして指定する機能があり、クラス自身の外部でインスタンスを作成できないようにすることができます。 JavaScript にはこれを行うネイティブな方法はありませんが、プライベート静的フラグを使用することで実現できます。

js
class PrivateConstructor {
 static #isInternalConstructing = false;
 constructor() {
 if (!PrivateConstructor.#isInternalConstructing) {
 throw new TypeError("PrivateConstructor は構築できません");
 }
 PrivateConstructor.#isInternalConstructing = false;
 // More initialization logic
 }
 static create() {
 PrivateConstructor.#isInternalConstructing = true;
 const instance = new PrivateConstructor();
 return instance;
 }
}
new PrivateConstructor(); // TypeError: PrivateConstructor は構築できません
PrivateConstructor.create(); // PrivateConstructor {}

仕様書

Specification
ECMAScript® 2026 Language Specification
# prod-PrivateIdentifier
ECMAScript® 2026 Language Specification
# prod-00OK517S

ブラウザーの互換性

javascript.classes.private_class_fields

javascript.classes.private_class_fields_in

javascript.classes.private_class_methods

関連情報

Help improve MDN

Learn how to contribute

This page was last modified on by MDN contributors.

AltStyle によって変換されたページ (->オリジナル) /