Symbol.hasInstance

Overrides what instanceof reports for a constructor or namespace object.

Signature
Symbol.hasInstance
// as implemented on a constructor:
static [Symbol.hasInstance](instance)
  • Added in JavaScript ES2015

Parameters

ParameterTypeDescription
$instanceanyThe left-hand operand of instanceof — the value being tested.

Return value

symbolThe well-known symbol used as the property key for the method instanceof calls. The method's own result is coerced to a boolean.

Errors

instanceof throws a TypeError if the right operand is not an object, or is not callable and defines no [Symbol.hasInstance].

When you write value instanceof C, the engine first looks up C[Symbol.hasInstance]. If that method exists it is called with value and its result is coerced to a boolean; otherwise the ordinary prototype-chain walk in Function.prototype[Symbol.hasInstance] runs.

When to reach for it

Two situations justify it. First, structural checks: define static [Symbol.hasInstance] so x instanceof Iterable asks whether x has the right shape rather than the right ancestor. Second, cross-realm identity: an array from an iframe fails instanceof Array, and a custom hook using Array.isArray() fixes that. The right operand does not even have to be a function — a plain object carrying this method works.

What trips people up

The property is non-writable and non-configurable on Function.prototype, so you cannot assign it on an ordinary function with fn[Symbol.hasInstance] = …; use a static class method or Object.defineProperty(). Overriding also removes the usual guarantees — instanceof can now return true for primitives and null, since the standard "non-object is always false" step is skipped entirely. Keep the method cheap and side-effect free; it runs on every check.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Make instanceof recognise arrays and other builtins that crossed a realm boundary
  • Expose a structural "does this implement my protocol?" check with familiar syntax
  • Give an abstract base a membership test that accepts unrelated implementors

Frequently asked questions

How do I make instanceof work across iframes or realms?

Give the constructor a static [Symbol.hasInstance] that performs a realm-independent check, such as Array.isArray(value) or a Symbol.for()-based brand, instead of relying on the prototype chain.

Why does fn[Symbol.hasInstance] = ... not work?

Because the inherited property on Function.prototype is non-writable and non-configurable, so plain assignment fails. Use a static class method or Object.defineProperty() on the function.

Does Symbol.hasInstance affect the prototype chain?

No. It replaces the check instanceof performs but changes nothing about inheritance, so Object.getPrototypeOf() and isPrototypeOf() still report the real relationship.

More examples

Installing the hook on a plain function

defineProperty is required because the inherited Function.prototype slot is neither writable nor configurable, as the final line shows. Note the hook now rejects genuine ArrayLike instances — you replace the default check, you do not extend it.

Example · javascript
function ArrayLike() {}
Object.defineProperty(ArrayLike, Symbol.hasInstance, {
  value: (v) => Array.isArray(v),
});

console.log([] instanceof ArrayLike);
console.log(new ArrayLike() instanceof ArrayLike);

const desc = Object.getOwnPropertyDescriptor(
  Function.prototype,
  Symbol.hasInstance,
);
console.log(desc.writable, desc.configurable);

The right operand need not be a function

A plain object with the method satisfies instanceof, and primitives now return true — the usual short-circuit for non-objects is bypassed. An object without the method and without [[Call]] still throws a TypeError.

Example · javascript
const Positive = {
  [Symbol.hasInstance](n) {
    return typeof n === "number" && n > 0;
  },
};

console.log(3 instanceof Positive);
console.log(-1 instanceof Positive);
console.log(null instanceof Positive);

try {
  1 instanceof {};
} catch (err) {
  console.log(err.constructor.name);
}

Discussion

  • Be the first to comment on this lesson.