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:

It can work with constructor functions, as well:

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

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:

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:

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:

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:

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:

The toString algorithm explores this returning the corresponding result.
Here is another example:

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

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

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.