in
演算子 は、指定されたオブジェクト (またはそのプロトタイプチェーン内のいずれかのオブジェクト) が指定されたプロパティを持っているかどうかをテストするために使用できます
const o1 = {'foo': 0};
console.log('foo' in o1); // true
const o2 = {};
console.log('foo' in o2); // false
const o3 = Object.create(o1);
console.log('foo' in o3); // true
プライベートブランドのチェック機能は、in
演算子に、プライベートなクラスのフィールド をサポートするように拡張します
class A {
static test(obj) {
console.log(#foo in obj);
}
#foo = 0;
}
A.test(new A()); // true
A.test({}); // false
class B {
#foo = 0;
}
A.test(new B()); // false; it's not the same #foo
プライベート name はそれらを定義するクラス内でのみ利用できるので、テストもクラス内で行う必要があります (たとえば、上の static test
などのメソッド内)。
サブクラスのインスタンスは、親クラスのプライベートフィールドを自身のプロパティとして受け取ります
class SubA extends A {};
A.test(new SubA()); // true
しかし、Object.create
で作成されたオブジェクト (または __proto__
セッターや Object.setPrototypeOf
を通じて後にプロトタイプが設定されたオブジェクト) は、プライベートフィールドを自身のプロパティとして受け取りません。プライベートフィールドの参照は自身のプロパティでのみ機能するので、in
演算子はこれらの継承されたフィールドを見つけられません
const a = new A();
const o = Object.create(a);
A.test(o); // false, private field is inherited and not owned
A.test(o.__proto__); // true
const o2 = {};
Object.setPrototypeOf(o2, a);
A.test(o2); // false, private field is inherited and not owned
A.test(o2.__proto__); // true
存在しないプライベートフィールドにアクセスすると、エラーがスローされます。通常のプロパティとは異なり、存在しないプロパティにアクセスすると undefined
が返されますが、スローされません。プライベートブランドのチェックが行われる前は、開発者は try
-catch
を使用して、オブジェクトが必要なプライベートフィールドを持っていない場合のフォールバックの動作を実装していました
class D {
use(obj) {
try {
obj.#foo;
} catch {
// Fallback for the case obj didn't have #foo
}
}
#foo = 0;
}
現在、プライベートブランドのチェックを使用すると、プライベートフィールドの存在をテストできます
class E {
use(obj) {
if (#foo in obj) {
obj.#foo;
} else {
// Fallback for the case obj didn't have #foo
}
}
#foo = 0;
}
ただし、注意してください。プライベートフィールドが 1 つあるからといって、オブジェクトにクラスで宣言されているすべてのプライベートフィールドがあるわけではありません。次の例は、クラスで宣言されている 2 つのプライベートフィールドのうちの 1 つしかない半完成のオブジェクトを示しています
let halfConstructed;
class F {
m() {
console.log(#x in this); // true
console.log(#y in this); // false
}
#x = 0;
#y = (() => {
halfConstructed = this;
throw 'error';
})();
}
try {
new F();
} catch {}
halfConstructed.m();
プライベートブランドのチェックのサポート #
- Chrome: バージョン 91 よりサポート
- Firefox: サポートなし
- Safari: サポートなし
- Node.js: サポートなし
- Babel: サポートなし