An array handed to your code from a same-origin `<iframe>` fails `value instanceof Array`. Explain why, and how you would make the check reliable.
answer
- one environment, one set of built-ins
- identity fails where structure matches
- the object is not a copy
- a slot, not a chain
- two package copies do the same thing
basics
~20 sEach realm has its own set of built-ins, so the iframe's Array is a different function object with a different Array.prototype. The value's chain holds the iframe's prototype, so the identity comparison fails. Use Array.isArray, which is realm-independent.
solid answer
~40 sAn iframe, a worker, or a Node `vm` context is a separate realm with its own global object and its own complete set of intrinsics. The iframe's `Array` and your page's `Array` are two distinct function objects with two distinct `Array.prototype` objects. Since `instanceof` compares by identity along the prototype chain, an array built inside the iframe carries the iframe's `Array.prototype` and never matches yours — so the check returns `false` even though the value is a genuine array. The reliable fix for arrays is `Array.isArray(value)`, which inspects an internal slot rather than the chain and therefore works across realms; `Object.prototype.toString.call(value)` reads the same kind of internal information. The same failure appears without realms at all when a bundle ships two copies of a library, giving you two unrelated class objects.
code
javascript · 12 linesconst frame = document.createElement('iframe');
document.body.appendChild(frame);
const foreign = new frame.contentWindow.Array(1, 2, 3);
console.log(foreign instanceof Array); // false — different realm
console.log(foreign.constructor === Array); // false
console.log(foreign.constructor.name); // "Array" — same name, other identity
console.log(Array.isArray(foreign)); // true
console.log(Object.prototype.toString.call(foreign)); // "[object Array]"
console.log(foreign.length); // 3 — it is a real arraygo deeper
Know that Array.isArray is the correct way to test for an array, and that instanceof can answer false for values that came from another window or frame.
Explain realms: each iframe or worker has its own intrinsics, so identity comparison against your Array.prototype fails even though the value is a genuine array.
Diagnose it in production — recognise the duplicate-package variant with no realms involved, and replace fragile chain checks with markers or exported predicates at trust boundaries.
Set the policy for cross-boundary type identity: which values may cross realms or package copies, what stable tag every shared type carries, and how dependency resolution is constrained so identity stays single.
## Realms, and why there is more than one Array A *realm* is a complete JavaScript execution environment: a global object plus a fresh set of intrinsic objects — `Object`, `Array`, `Function`, `Error`, `Promise` and their prototypes. Each same-origin `<iframe>`, each worker, and each Node `vm` context gets its own realm. Objects can cross freely between same-origin realms without being copied, so you can end up holding a live reference to an object whose prototype chain terminates in someone else's intrinsics. ```js const frame = document.createElement('iframe'); document.body.appendChild(frame); const foreign = new frame.contentWindow.Array(1, 2, 3); foreign instanceof Array; // false Object.getPrototypeOf(foreign) === Array.prototype; // false Object.getPrototypeOf(foreign) === frame.contentWindow.Array.prototype; // true ``` Nothing is broken here. `instanceof` is doing exactly what it always does: it reads *your* `Array.prototype` and searches the value's chain for that specific object. The chain contains a structurally identical but distinct object, and identity comparison says no. ## The same failure without any iframe Realms are the textbook case, but the version that actually costs teams time has no realms in it. If a bundle or a `node_modules` tree contains two copies of the same library — say two versions of an error class, or a peer dependency installed twice — then two distinct class objects exist in one realm. A value produced by copy A fails `instanceof` against copy B: ```js // module built against copy A throw new ValidationError('bad'); // consumer that resolved copy B catch (e) { if (e instanceof ValidationError) { /* never runs */ } } ``` The symptom is identical: a value that obviously *is* the right thing fails a chain-identity test, and the error falls through to a generic handler. ## Diagnosing it Three checks separate this from an ordinary bug quickly: 1. `Object.prototype.toString.call(value)` still reports `"[object Array]"`, so the value really is an array. 2. `value.constructor === Array` is also `false`, and `value.constructor.name` is still `"Array"` — two functions with the same name and different identity is the signature of the problem. 3. `Object.getPrototypeOf(value) === Array.prototype` is `false` while the object behaves like an array in every other way. For the duplicate-package variant, resolving the module twice and comparing the exported class objects with `===` confirms it directly. ## Checks that survive it For arrays specifically, the language provides a purpose-built answer: ```js Array.isArray(foreign); // true, regardless of realm ``` `Array.isArray` does not consult the prototype chain at all; it asks whether the value is an array exotic object, which is a property of the value itself. That is why it is the correct check whenever a value might come from anywhere. `Object.prototype.toString.call(value)` gives similar cross-realm-safe answers for several built-in types, though `Symbol.toStringTag` lets user objects influence the result, so it is a hint rather than a guarantee. For **your own** types there is no built-in equivalent, so the durable patterns are: - **Duck typing on a stable marker.** Give the type an own or prototype property with a namespaced string or symbol key and test for that instead of the chain. `Symbol.for('myapp.ValidationError')` is registered in a cross-realm symbol registry, so the same key resolves to the same symbol in every realm — a genuinely realm-proof marker. - **A static predicate.** Export `ValidationError.isValidationError(x)` alongside the class, implemented with the marker check, so consumers never write the fragile test themselves. - **Fix the duplication.** For the two-copies case, the real remedy is dependency hygiene — deduplicate, or declare the shared library a peer dependency — because two copies also mean two module-level caches and two sets of any other module state. ## When instanceof is still the right tool None of this makes `instanceof` bad. Within one realm, with one copy of the code, checking your own error subclasses in a `catch` block is idiomatic and readable. The judgment being tested is knowing where the boundary is: the moment a value can arrive from an iframe, a worker, a deserialiser, or a differently-resolved copy of a package, a chain-identity check is answering a narrower question than the one you meant to ask, and you need a check based on something intrinsic to the value rather than on which prototype object it happens to point at.
- Why does `Array.isArray` succeed where `instanceof Array` fails?`Array.isArray` does not look at the prototype chain. It asks whether the value is an array exotic object — a fact recorded in the value itself, not in what it inherits from. Realm boundaries change which prototype objects exist, but they cannot change what kind of object a value is, so the answer stays correct wherever the array was created.
- What is the equivalent failure for `Error`, and what breaks because of it?An error thrown inside an iframe or worker fails `e instanceof Error` in the outer realm for the same reason. Error-handling code that branches on error subclasses then falls through to a generic handler, so a recoverable condition gets reported as an unknown failure. Checking a namespaced marker property, or a registered symbol, keeps working across the boundary.
- How would you make your own class recognisable across realms?Attach a stable marker rather than relying on the chain: a property keyed with `Symbol.for('myapp.Thing')`, which resolves to the same symbol in every realm through the global symbol registry, or a namespaced string field. Export a static predicate such as `Thing.isThing(x)` that performs the check, so consumers have one correct way to ask.
saying these in an interview costs you the question
- Claiming instanceof Array always works for real arrays
- Assuming same-origin means the same intrinsic objects
- Thinking the value was copied or degraded in transit
- Believing typeof can distinguish arrays from objects
- Assuming two package copies cannot break instanceof