A realm (a Realm Record in the spec) bundles a set of intrinsic objects, a global object and Global Environment Record, and the code loaded into them. Intrinsics are the built-ins the engine creates for you: %Array%, %Array.prototype%, %Object%, %Error%, and so on. CreateIntrinsics builds a brand-new set for each realm.
Where realms come from:
- A same-origin
<iframe>(or a popup) gets its own realm, soiframe.contentWindow.Arrayis a different function from yourArray. - Node's
vmcontexts create realms as well. - Workers and the main thread have separate realms, but they can't share objects directly anyway.
Why instanceof breaks: x instanceof Array checks whether Array.prototype is in x's prototype chain. An array made in another realm inherits from that realm's Array.prototype, which is a different object. So foreignArray instanceof Array is false, even though it is a real array. The same applies to Object, Function, Error, Date, Map, and the rest.
Robust checks that don't depend on identity:
Array.isArray(x)looks at the object's exotic internal kind (IsArray), so it works across realms.Error.isError(x)does the same for errors (a newer API; check support).Object.prototype.toString.call(x)readsSymbol.toStringTag, which is mostly reliable but spoofable.- Duck typing (
typeof x.then === 'function') for promises and iterables.
Some things are shared across realms. Well-known symbols (Symbol.iterator) and registered symbols (Symbol.for('k')) are the same in every realm, and primitives have no realm at all.