Mastering instanceof: Is Your JavaScript Object What You Think?
👋 Introduction
When writing JavaScript, especially in large applications, understanding the type of your objects is crucial. While typeof works fine for primitives, it quickly falls short when working with classes, constructors, or complex data structures.
That’s where instanceof comes in. Think of it as JavaScript’s version of a DNA test for objects—it helps confirm whether an object was created from a particular constructor.
Let’s explore how instanceof works, where it excels, its limitations, and how to use it correctly.
🔍 What Does instanceof Do?
The instanceof operator checks if an object is an instance of a particular constructor function (i.e., if it appears somewhere in the prototype chain).
function Vehicle(make) {
this.make = make;
}
const myVehicle = new Vehicle('Tesla');
console.log(myVehicle instanceof Vehicle); // true
console.log(myVehicle instanceof Object); // true
console.log(myVehicle instanceof Array); // falseExplanation:
- ✅
myVehicleis an instance ofVehicle - ✅ It’s also an
Object, since all objects inherit fromObject - ❌ It’s not an
Array
⚙️ How instanceof Works Internally
instanceof climbs the prototype chain to see if constructor.prototype appears anywhere.
function BaseEntity() {}
function SubEntity() {}
SubEntity.prototype = Object.create(BaseEntity.prototype); // Inherit BaseEntity
const sampleInstance = new SubEntity();
console.log(sampleInstance instanceof SubEntity); // true
console.log(sampleInstance instanceof BaseEntity); // trueHere, SubEntity inherits from BaseEntity, so instances of SubEntity are also instances of BaseEntity.
📦 Real-World Use Case: API Response Validation
instanceof is useful for verifying types, especially when working with multiple possible object shapes:
class ResponseWrapper {
constructor(payload) {
this.payload = payload;
this.timestamp = new Date();
}
}
function processResponse(data) {
if (data instanceof ResponseWrapper) {
console.log('✅ Valid response:', data.payload);
} else {
console.error('❌ Invalid response format');
}
}This ensures the function only processes valid instances of ResponseWrapper.
🎯 More Examples & Edge Cases
Primitive vs Object Wrapper
console.log('world' instanceof String); // false
console.log(new String('world') instanceof String); // truePrimitives are not objects, so instanceof returns false.
Cross-Context (Iframe) Pitfall
// Assume `externalObj` was created inside an iframe
console.log(externalObj instanceof SomeClass); // false (different JS realm)Objects from different browser contexts (like iframes) may fail even if they look identical.
🆚 typeof vs instanceof
| Use Case | typeof | instanceof |
|---|---|---|
| Primitives | ✅ Works well | ❌ Doesn’t apply |
| Object Instances | ❌ Too generic | ✅ Ideal for constructors |
| Cross-Realm Issues | ✅ Safe | ❌ Not reliable |
const plainStr = 'text';
const wrappedStr = new String('text');
console.log(typeof plainStr); // "string"
console.log(typeof wrappedStr); // "object"
console.log(plainStr instanceof String); // false
console.log(wrappedStr instanceof String); // true✍️ Custom Implementation of instanceof
Here’s how you can write your own version to better understand how it works:
function customInstanceof(target, Constructor) {
if (target === null || typeof target !== 'object') return false;
let currentProto = Object.getPrototypeOf(target);
while (currentProto) {
if (currentProto === Constructor.prototype) return true;
currentProto = Object.getPrototypeOf(currentProto);
}
return false;
}
// Test
function User() {}
const sampleUser = new User();
console.log(customInstanceof(sampleUser, User)); // true
console.log(customInstanceof(sampleUser, Object)); // true
console.log(customInstanceof(sampleUser, Array)); // false⚠️ Caution: Changing Prototypes Can Break It
function Tool() {}
const hammer = new Tool();
console.log(hammer instanceof Tool); // true
Tool.prototype = {}; // Change prototype
console.log(hammer instanceof Tool); // falseReassigning the prototype after object creation breaks the relationship.
🏛️ instanceof with ES6 Classes
class Manager {}
class Developer extends Manager {}
const engineer = new Developer();
console.log(engineer instanceof Developer); // true
console.log(engineer instanceof Manager); // trueClass inheritance under ES6 still uses prototype chains, so instanceof works the same.
✅ Conclusion
The instanceof operator is a powerful and underused tool in JavaScript. With it, you can:
- Check an object’s constructor
- Walk the prototype chain
- Validate runtime types more reliably
Just remember its limitations, like cross-context behavior and sensitivity to prototype changes. Used thoughtfully, it helps make your JavaScript applications safer and more predictable.