w3docs logo

JavaScript Class Checking: "instanceof"

The operator instanceof is targeted at checking whether an object belongs to a specific class. It also helps to take inheritance into account.

Now, let’s use it to build a polymorphic function, which treats arguments differently depending on their type.

The instanceof operator

The following syntax is used for the instanceof operator:

obj instanceof Class

It may return true in case the object belongs to the Class or the class inheriting from it.

Here is an example:

w3docs logo Javascript instanceof operator
class Dog {} let dog = new Dog(); // is it an object of Dog class? console.log(dog instanceof Dog); // true

It can work with constructor functions, as well:

w3docs logo Javascript instanceof operator
// instead of class function Dog() {} console.log(new Dog() instanceof Dog); // true

Also, it works with built-in classes, such as Array:

w3docs logo Javascript class checking: “instanceof”
let arr = [1, 2, 3]; console.log(arr instanceof Array); // true console.log(arr instanceof Object); // true

Please, take into consideration that arr belongs to the Object class. The reason is that Array prototypically inherits from Object.

As a rule, the instanceof studies the prototype chain for the check. It is also possible to apply a custom logic inside the static method Symbol.hasInstance.

The obj instanceof Class algorithm works as follows:

w3docs logo Javascript instanceof operator
// setup instanceOf check that assumes that // anything with canEat property is an animal class Animal { static[Symbol.hasInstance](obj) { if (obj.eats) return true; } } let obj = { eats: true }; console.log(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) is called

So, if there exists a static method Symbol.hasInstance, it can be called Class[Symbol.hasInstance](obj). It may either return true or false.

But most of the cases don’t include Symbol.hasInstance. In such cases, you need to follow the standard logic: obj instanceOf Class will check whether Class.prototype is the same as one of the prototypes in the obj prototype chain.

Here is an example:

obj.__proto__ === Class.prototype ?
  obj.__proto__.__proto__ === Class.prototype ?
  obj.__proto__.__proto__.__proto__ === Class.prototype ?
  ...
// if any answer is true, return true
// otherwise, if we reach the end of the chain, return false

In the example given above dog.__proto__ === Dog.prototype, the answer is given immediately.

If there is an inheritance, the match is at the second step, as follows:

w3docs logo Javascript object instanceof class
class Animal {} class Dog extends Animal {} let dog = new Dog(); console.log(dog instanceof Dog); // true // dog.__proto__ === Dog.prototype // dog.__proto__.__proto__ === Animal.prototype

Let’s take a look at the illustrations below:

Another method can be highlighted. It’s objA.isPrototypeOf(objB), which returns true in case objA is inside the chain of prototypes and Class.prototype matters.

It may lead to extraordinary results when a prototype property is transformed after the object is generated.

Here is an example:

w3docs logo Javascript object instanceof class
function Dog() {} let dog = new Dog(); // changed the prototype Dog.prototype = {}; // not a dog any more! console.log(dog instanceof Dog); // false

Bonus: Object.prototype.toString for the type

As it was already noted, plain objects can be converted to a string as [object Object], like here:

w3docs logo Javascript object prototype to string
let obj = {}; console.log(obj); // [object Object] console.log(obj.toString()); // the same

It’s their implementation of toString. But, there exists a hidden feature, making toString more robust than that. It may be used as an extended typeof, as well as an alternative for instanceof.

The built-in toString may be extracted from the object, as well as executed in any other value’s context. The result of it depends on that value.

  • It can be [object Number] for a number.
  • It can be [object Boolean] for a boolean.
  • It can be [object Null] for null.
  • It can be [object Undefined] for undefined.
  • [object Array] : for arrays.

It’s demonstrated in the example below:

w3docs logo Javascript object prototype tostring
// copy toString method into a variable for convenience let objToString = Object.prototype.toString; let arr = []; // what type is this? console.log(objToString.call(arr)); // [object Array]

The toString algorithm explores this returning the corresponding result.

Here is another example:

w3docs logo Javascript object prototype tostring
let str = Object.prototype.toString; console.log(str.call(123)); // [object Number] console.log(str.call(null)); // [object Null] console.log(str.call(alert)); // [object Function]

Symbol.toStringTag

The Object toString behavior may be customized, applying a unique object property that is Symbol.toStringTag.

The example is as follows:

w3docs logo Javascript object prototype tostringtag
let animal = { [Symbol.toStringTag]: "Animal" }; console.log({}.toString.call(animal)); // [object Animal]

There is such property for most of the environment-specific objects. For instance:

w3docs logo Javascript object prototype tostringtag
// toStringTag for the environment-specific object and class: console.log(window[Symbol.toStringTag]); // window console.log(XMLHttpRequest.prototype[Symbol.toStringTag]); // XMLHttpRequest console.log({}.toString.call(window)); // [object Window] console.log({}.toString.call(new XMLHttpRequest())); // [object XMLHttpRequest]

So, you can notice that the result is Symbol.toStringTag that is wrapped into [object ...].

The {}.toString.call may be used instead of instanceof for built-in objects whenever it’s necessary to receive the type as a string rather than just check.


Do you find this helpful?