How to Use instanceof for Reliable Type Checks in JS

👋 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).

js
123456789
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);       // false

Explanation:

  • myVehicle is an instance of Vehicle
  • ✅ It’s also an Object, since all objects inherit from Object
  • ❌ It’s not an Array

⚙️ How instanceof Works Internally

instanceof climbs the prototype chain to see if constructor.prototype appears anywhere.

js
123456789
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);  // true

Here, 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:

js
1234567891011121314
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

js
12
console.log('world' instanceof String);           // false
console.log(new String('world') instanceof String); // true

Primitives are not objects, so instanceof returns false.

Cross-Context (Iframe) Pitfall

js
12
// 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 Casetypeofinstanceof
Primitives✅ Works well❌ Doesn’t apply
Object Instances❌ Too generic✅ Ideal for constructors
Cross-Realm Issues✅ Safe❌ Not reliable
js
1234567
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:

js
123456789101112131415161718
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

js
1234567
function Tool() {}
const hammer = new Tool();

console.log(hammer instanceof Tool); // true

Tool.prototype = {}; // Change prototype
console.log(hammer instanceof Tool); // false

Reassigning the prototype after object creation breaks the relationship.

🏛️ instanceof with ES6 Classes

js
1234567
class Manager {}
class Developer extends Manager {}

const engineer = new Developer();

console.log(engineer instanceof Developer); // true
console.log(engineer instanceof Manager);   // true

Class 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.