What is the difference between typeof and instanceof and when should one be used vs. the other?
Solution 1:
Use instanceof
for custom types:
var ClassFirst = function () {};
var ClassSecond = function () {};
var instance = new ClassFirst();
typeof instance; // object
typeof instance == 'ClassFirst'; // false
instance instanceof Object; // true
instance instanceof ClassFirst; // true
instance instanceof ClassSecond; // false
Use typeof
for simple built in types:
'example string' instanceof String; // false
typeof 'example string' == 'string'; // true
'example string' instanceof Object; // false
typeof 'example string' == 'object'; // false
true instanceof Boolean; // false
typeof true == 'boolean'; // true
99.99 instanceof Number; // false
typeof 99.99 == 'number'; // true
function() {} instanceof Function; // true
typeof function() {} == 'function'; // true
Use instanceof
for complex built in types:
/regularexpression/ instanceof RegExp; // true
typeof /regularexpression/; // object
[] instanceof Array; // true
typeof []; //object
{} instanceof Object; // true
typeof {}; // object
And the last one is a little bit tricky:
typeof null; // object
Solution 2:
Both are similar in functionality because they both return type information, however I personally prefer instanceof
because it's comparing actual types rather than strings. Type comparison is less prone to human error, and it's technically faster since it's comparing pointers in memory rather than doing whole string comparisons.
Solution 3:
A good reason to use typeof is if the variable may be undefined.
alert(typeof undefinedVariable); // alerts the string "undefined"
alert(undefinedVariable instanceof Object); // throws an exception
A good reason to use instanceof is if the variable may be null.
var myNullVar = null;
alert(typeof myNullVar ); // alerts the string "object"
alert(myNullVar instanceof Object); // alerts "false"
So really in my opinion it would depend on what type of possible data you are checking.
Solution 4:
To make things clear, you need to know two facts:
- The instanceof operator tests whether the prototype property of a constructor appears anywhere in the prototypes chain of an object. In most cases this mean that the object was created by using this constructor or on of its descendant. But also prototype may be set explicitly by
Object.setPrototypeOf()
method (ECMAScript 2015) or by the__proto__
property (old browsers, deprecated). Changing the prototype of an object is not recommended though, because of performance issues.
Thus instanceof is applicable only to objects. In most cases you aren't using constructors to create strings or numbers. You can. But you almost never do.
Also instanceof can't check, exactly which constructor was used to create the object, but will return true, even if object is derived from class which being checked. In most cases this is the desired behavior, but sometimes it's not. So you need to keep that mind.
Another problem is that different scopes have different execution environments. This means that they have different built-ins (different global object, different constructors, etc.). This may result in unexpected results.
For example, [] instanceof window.frames[0].Array
will return false
, because Array.prototype !== window.frames[0].Array
and arrays inherit from the former.
Also, it cannot be used on undefined value, because it don't have a prototype.
- The typeof operator tests whether value belong to one of six basic types: "number", "string", "boolean", "object", "function" or "undefined". Where the string "object" belong all objects (except functions, which are objects, but have its own value in typeof operator), and also "null" value and arrays (for "null" it's a bug, but this bug is so old, so it's become a standard). It doesn't rely on constructors and can be used even if value is undefined. But it's doesn't give any details about objects. So if you needed it, go to instanceof.
Now let's talk about one tricky thing. What if you use constructor to create a primitive type?
let num = new Number(5);
console.log(num instanceof Number); // print true
console.log(typeof num); // print object
num++; //num is object right now but still can be handled as number
//and after that:
console.log(num instanceof Number); // print false
console.log(typeof num); // print number
Seems like magic. But it is not. It's so-called boxing (wrapping primitive value by object) and unboxing (extracting wrapped primitive value from object). Such kind of code seems to be "a bit" fragile. Of course you can just avoid creating primitive type with constructors. But there is another possible situation, when boxing may hit you. When you use Function.call() or Function.apply() on a primitive type.
function test(){
console.log(typeof this);
}
test.apply(5);
To avoiding this you can use strict mode:
function test(){
'use strict';
console.log(typeof this);
}
test.apply(5);
upd: Since ECMAScript 2015, there is one more type called Symbol, which has its own typeof == "symbol".
console.log(typeof Symbol());
// expected output: "symbol"
You can read about it on MDN: (Symbol, typeof).
Solution 5:
I've discovered some really interesting (read as "horrible") behavior in Safari 5 and Internet Explorer 9. I was using this with great success in Chrome and Firefox.
if (typeof this === 'string') {
doStuffWith(this);
}
Then I test in IE9, and it doesn't work at all. Big surprise. But in Safari, it's intermittent! So I start debugging, and I find that Internet Explorer is always returning false
. But the weirdest thing is that Safari seems to be doing some kind of optimization in its JavaScript VM where it is true
the first time, but false
every time you hit reload!
My brain almost exploded.
So now I've settled on this:
if (this instanceof String || typeof this === 'string')
doStuffWith(this.toString());
}
And now everything works great. Note that you can call "a string".toString()
and it just returns a copy of the string, i.e.
"a string".toString() === new String("a string").toString(); // true
So I'll be using both from now on.