9

I understand why you need to use Object.prototype.toString() or String() for typechecking arrays, but isn't typeof sufficient for typechecking functions and strings? For example the polyfill on MDN for Array.isArray uses:

Object.prototype.toString.call(arg) == '[object Array]';

It's pretty clear in the case of arrays because you can't use typeof to check for arrays. Valentine uses instanceof for this:

ar instanceof Array

But for strings/functions/booleans/numbers, why not use typeof?

jQuery and Underscore both use something like this to check for functions:

Object.prototype.toString.call(obj) == '[object Function]';

Isn't that equivalent to doing this?

typeof obj === 'function'

or even this?

obj instanceof Function
Nathan Kleyn
  • 5,103
  • 3
  • 32
  • 49
ryanve
  • 50,076
  • 30
  • 102
  • 137

2 Answers2

17

Ok I think I figured out why you see the toString usage. Consider this:

var toString = Object.prototype.toString;
var strLit = 'example';
var strStr = String('example')​;
var strObj = new String('example');

console.log(typeof strLit); // string    
console.log(typeof strStr); // string
console.log(typeof strObj); // object

console.log(strLit instanceof String); // false
console.log(strStr instanceof String); // false
console.log(strObj instanceof String); // true

console.log(toString.call(strLit)); // [object String]
console.log(toString.call(strStr)); // [object String]
console.log(toString.call(strObj)); // [object String]

ryanve
  • 50,076
  • 30
  • 102
  • 137
  • 1
    Do note that it does not work with Promises, at least in Chrome in Firefox. `typeof mypromise === 'object`, `toString.call(mypromise) === '[Object]'`, but `mypromise instanceof Promise === true` – Hurelu May 29 '15 at 01:19
  • @Hurelu That makes sense because `Promise` inherits from `Object`. I get `"[object Object]"` using `.call` but if you do `promise.toString` it gives `"[object Promise]"`. See https://stackoverflow.com/q/27746304/770127 – ryanve May 31 '18 at 18:26
1

The first reason I can think of is that typeof null returns object, which is not usually what you want (since null is not an object, but a type in its own right).

However, Object.prototype.toString.call(null) returns [object Null].

But, as you suggest, if you expect something to be a string or other type that works well with typeof, I see no reason why you can't use typeof (and I regularly do use typeof in that case).

Another reason libraries such as those you mention use their chosen method may simply be for consistency. You can use typeof to check for an Array, so use another method and stick to that throughout.

For some more information, Angus Croll has an excellent article on the typeof operator.

James Allardice
  • 164,175
  • 21
  • 332
  • 312
  • I'm talking about checking stuff the seemingly should work without a hitch like strings/functions/booleans/numbers – ryanve Mar 01 '12 at 08:17
  • Do note that it does not work with Promises, at least in Chrome in firefox. `typeof mypromise === 'object`, `toString.call(mypromise) === '[Object]'`, but `mypromise instanceof Promise === true` – Hurelu May 29 '15 at 01:15
  • @Hurelu - In latest stable Chrome I get `"[object Promise]"` for `Object.prototype.toString.call(mypromise)` – James Allardice May 29 '15 at 08:31
  • Funny. Just upgraded to Chrome 43.0.2357.81 and I still get `[object Object]`. I only checked through the console. I also checked again in Firefox and [object Promise] now comes correctly. Because of these mixed results, I would still caution against this method for detecting promises reliably. – Hurelu May 29 '15 at 13:27