Type checking is fundamental to writing robust JavaScript applications. While many developers reach for typeof for basic checks, instanceof offers powerful prototype-based type detection that every serious JavaScript developer should master. This guide explores how instanceof works, when to use it, and common pitfalls to avoid. Understanding these type-checking mechanisms is essential for building reliable web applications that handle data correctly across your codebase.
What is instanceof?
The instanceof operator in JavaScript tests whether the prototype property of a constructor appears anywhere in the prototype chain of an object. The return value is a boolean value, making it straightforward to use in conditional logic.
Key Characteristics
- Primary purpose: Check object inheritance and constructor relationships
- Returns:
trueorfalseonly - Works with: Custom classes, built-in constructors, and inheritance chains
- Cannot be used with: Primitives (numbers, strings, booleans, null, undefined, symbols)
- Browser support: Widely supported across all modern browsers since early JavaScript versions
Syntax
object instanceof constructor
Parameters:
object: The object to test - must be an object, not a primitiveconstructor: The constructor function or class to test against
Returns: Boolean - true if constructor.prototype exists in the prototype chain, false otherwise
Throws: TypeError if constructor is not a function or lacks a Symbol.hasInstance method
1// Basic instanceof usage2class Animal {}3class Dog extends Animal {}4 5const buddy = new Dog();6 7console.log(buddy instanceof Dog); // true8console.log(buddy instanceof Animal); // true (inheritance)9console.log(buddy instanceof Object); // true (all objects inherit from Object)10 11// With constructor functions12function Car(make) {13 this.make = make;14}15 16const honda = new Car('Honda');17console.log(honda instanceof Car); // trueHow instanceof Works: The Prototype Chain
The instanceof operator walks up the prototype chain looking for constructor.prototype. This is fundamentally different from typeof which checks the internal [[PrimitiveValue]] slot for primitives.
When working with Error handling in JavaScript, understanding the prototype chain becomes crucial for proper exception management and debugging. The prototype chain also plays a significant role in JavaScript API design, where proper object relationships ensure clean and maintainable code.
Prototype Chain Visualization
buddy (instance)
↓ [[Prototype]]
Dog.prototype
↓ [[Prototype]]
Animal.prototype
↓ [[Prototype]]
Object.prototype
↓ [[Prototype]]
null
When checking buddy instanceof Animal:
- JavaScript looks at
buddy.__proto__→Dog.prototype Dog.prototype.__proto__→Animal.prototype- Found match! Returns
true
1// Prototype manipulation affects instanceof results2function Widget() {}3const widget = new Widget();4 5// Reassigning prototype breaks instanceof checks6Widget.prototype = {};7const newWidget = new Widget();8 9console.log(widget instanceof Widget); // false (original prototype missing)10console.log(newWidget instanceof Widget); // true (new prototype exists)instanceof vs typeof: When to Use Each
Choosing between instanceof and typeof depends on what you're trying to check. Here's a clear comparison:
Comparison Table
| Feature | typeof | instanceof |
|---|---|---|
| Primitives | ✓ Works | ✗ Returns false |
| Objects | ✓ Returns "object" | ✓ Checks constructor |
| Arrays | Returns "object" | ✓ Returns true for Array |
| Custom Classes | Returns "object" | ✓ Returns true |
| null | Returns "object" (bug) | Returns false |
| Functions | Returns "function" | ✓ Works |
| Prototype Chain | ✗ Ignores | ✓ Checks chain |
When to Use typeof
- Checking for undefined variables
- Distinguishing between primitives (string, number, boolean, symbol)
- Checking if a value is a function
- Basic type validation before further processing
When to Use instanceof
- Checking if an object is an instance of a custom class
- Verifying inheritance relationships
- Validating API responses against expected object shapes
- Type guards in switch statements for class hierarchies
- Checking for built-in types like Array, Date, RegExp, Error, Promise
Common Use Cases
Custom Class Detection
class ApiResponse {
constructor(data, status) {
this.data = data;
this.status = status;
}
isSuccess() {
return this.status >= 200 && this.status < 300;
}
}
function handleResponse(response) {
if (response instanceof ApiResponse) {
console.log(`API call ${response.isSuccess() ? 'succeeded' : 'failed'}`);
} else {
console.warn('Unexpected response type');
}
}
Inheritance Checking
class Shape {}
class Circle extends Shape {}
class Rectangle extends Shape {}
function processShape(shape) {
if (shape instanceof Circle) {
return Math.PI * shape.radius ** 2;
} else if (shape instanceof Rectangle) {
return shape.width * shape.height;
} else if (shape instanceof Shape) {
return 0; // Generic shape
}
throw new Error('Invalid shape');
}
Built-in Type Validation
function processData(data) {
if (data instanceof Array) {
return data.map(item => item * 2);
}
if (data instanceof Map) {
return Array.from(data.entries());
}
if (data instanceof Promise) {
return data.then(result => processData(result));
}
throw new Error('Unsupported data type');
}
Advanced: Customizing instanceof with Symbol.hasInstance
The well-known Symbol.hasInstance allows you to customize instanceof behavior for custom classes. Implement a static [Symbol.hasInstance](obj) method on your constructor.
Custom Symbol.hasInstance Example
class Iterable {
static [Symbol.hasInstance](obj) {
return obj !== null &&
typeof obj === 'object' &&
typeof obj[Symbol.iterator] === 'function';
}
}
const myArray = [1, 2, 3];
const myString = 'hello';
const myObject = { name: 'test' };
console.log(myArray instanceof Iterable); // true (has iterator)
console.log(myString instanceof Iterable); // true (strings are iterable)
console.log(myObject instanceof Iterable); // false (no iterator)
Practical Protocol Checking
class Drawable {
static [Symbol.hasInstance](obj) {
return obj !== null &&
typeof obj === 'object' &&
typeof obj.draw === 'function';
}
}
const circle = { draw() { console.log('Circle'); } };
console.log(circle instanceof Drawable); // true, even without inheritance
This pattern is particularly useful when working with default parameters and creating flexible API designs that can handle multiple input types gracefully.
Edge Cases and Common Pitfalls
The null and undefined Problem
console.log(null instanceof Object); // false
console.log(undefined instanceof Object); // false
// typeof returns 'object' for null (historical bug)
console.log(typeof null); // 'object'
Primitives Don't Work with instanceof
const message = 'hello';
const number = 42;
console.log(message instanceof String); // false (primitive)
console.log(number instanceof Number); // false
// Wrapped primitives work:
const wrappedMessage = new String('hello');
console.log(wrappedMessage instanceof String); // true
Cross-Realm Objects
Different browsing contexts (frames, windows) have separate constructor copies:
// In iframe context
const iframeArray = iframe.contentWindow.Array;
// This might return false!
console.log(someArray instanceof iframeArray);
// Solution: Use Array.isArray()
console.log(Array.isArray(someArray)); // true
Object.create(null)
Objects created without Object.prototype don't work as expected:
const orphan = Object.create(null);
console.log(orphan instanceof Object); // false (no Object.prototype)
console.log(typeof orphan); // 'object'
Understanding these edge cases is essential when building robust JavaScript applications. Combined with proper error handling techniques, you can create more resilient code that gracefully handles unexpected inputs.
Follow these guidelines for robust type checking
Use instanceof for Objects
Check object inheritance and constructor relationships with instanceof
Use typeof for Primitives
Distinguish between string, number, boolean, symbol with typeof
Prefer Array.isArray()
Use for array detection when cross-realm compatibility matters
Avoid Primitive Checks
instanceof doesn't work with primitives without wrapping
Use Symbol.hasInstance
For custom type protocols instead of modifying prototypes
Handle null Explicitly
instanceof returns false, but typeof returns 'object'