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
由於私有名稱僅在定義它們的類別內可用,因此測試也必須在類別內進行,例如在上述 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;
}
但請注意,一個私有欄位的存在並不能保證物件具有類別中宣告的所有私有欄位!以下範例顯示一個半建構的物件,其中只有一個在類別中宣告的兩個私有欄位
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: 不支援