https://v8.dev/features/private-brand-checks V8 Show navigation * Home * Blog * Docs * JS/Wasm features * Research Private brand checks a.k.a. #foo in obj Published 14 April 2021 * Tagged with ECMAScript The in operator can be used for testing whether the given object (or any object in its prototype chain) has the given property: 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 The private brand checks feature extends the in operator to support private class fields: 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 Since private names are only available inside the class which defines them, the test must also occur inside the class, for example in a method like static test above. Subclass instances receive private fields from the parent class as own-properties: class SubA extends A {}; A.test(new SubA()); // true But objects created with with Object.create (or that have the prototype set later via the __proto__ setter or Object.setPrototypeOf) don't receive the private fields as own-properties. Because private field lookup only works on own-properties, the in operator does not find these inherited fields: 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.setProrotypeOf(o2, a); A.test(o2); // false, private field is inherited and not owned A.test(o2.__proto__); // true Accessing a non-existing private field throws an error - unlike for normal properties, where accessing a non-existent property returns undefined but doesn't throw. Before the private brand checks, the developers have been forced to use a try-catch for implementing fall-back behavior for cases where an object doesn't have the needed private field: class D { use(obj) { try { obj.#foo; } catch { // Fallback for the case obj didn't have #foo } } #foo = 0; } Now the existence of the private field can be tested using a private brand check: class E { use(obj) { if (#foo in obj) { obj.#foo; } else { // Fallback for the case obj didn't have #foo } } #foo = 0; } But beware - the existence of one private field does not guarantee that the object has all the private fields declared in a class! The following example shows a half-constructed object which has only one of the two private fields declared in its class: 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(); Private brand check support # * Chrome: supported since version 91 * Firefox: no support * Safari: no support * Node.js: no support * Babel: no support about this feature support listing [marja-holtta] Posted by Marja Holtta (@marjakh). Retweet this article! Branding * Terms * Privacy * Twitter * Edit this page on GitHub Except as otherwise noted, any code samples from the V8 project are licensed under V8's BSD-style license. Other content on this page is licensed under the Creative Commons Attribution 3.0 License. For details, see our site policies.