In JavaScript everything is an object (or may at least be treated as an object), except primitives (booleans, null, numbers, strings and the value undefined
(and symbol in ES6)):
console.log(typeof true); // boolean
console.log(typeof 0); // number
console.log(typeof ""); // string
console.log(typeof undefined); // undefined
console.log(typeof null); // object
console.log(typeof []); // object
console.log(typeof {}); // object
console.log(typeof function () {}); // function
As you can see objects, arrays and the value null
are all considered objects (null
is a reference to an object which doesn't exist). Functions are distinguished because they are a special type of callable objects. However they are still objects.
On the other hand the literals true
, 0
, ""
and undefined
are not objects. They are primitive values in JavaScript. However booleans, numbers and strings also have constructors Boolean
, Number
and String
respectively which wrap their respective primitives to provide added functionality:
console.log(typeof new Boolean(true)); // object
console.log(typeof new Number(0)); // object
console.log(typeof new String("")); // object
As you can see when primitive values are wrapped within the Boolean
, Number
and String
constructors respectively they become objects. The instanceof
operator only works for objects (which is why it returns false
for primitive values):
console.log(true instanceof Boolean); // false
console.log(0 instanceof Number); // false
console.log("" instanceof String); // false
console.log(new Boolean(true) instanceof Boolean); // true
console.log(new Number(0) instanceof Number); // true
console.log(new String("") instanceof String); // true
As you can see both typeof
and instanceof
are insufficient to test whether a value is a boolean, a number or a string - typeof
only works for primitive booleans, numbers and strings; and instanceof
doesn't work for primitive booleans, numbers and strings.
Fortunately there's a simple solution to this problem. The default implementation of toString
(i.e. as it's natively defined on Object.prototype.toString
) returns the internal [[Class]]
property of both primitive values and objects:
function classOf(value) {
return Object.prototype.toString.call(value);
}
console.log(classOf(true)); // [object Boolean]
console.log(classOf(0)); // [object Number]
console.log(classOf("")); // [object String]
console.log(classOf(new Boolean(true))); // [object Boolean]
console.log(classOf(new Number(0))); // [object Number]
console.log(classOf(new String(""))); // [object String]
The internal [[Class]]
property of a value is much more useful than the typeof
the value. We can use Object.prototype.toString
to create our own (more useful) version of the typeof
operator as follows:
function typeOf(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
console.log(typeOf(true)); // Boolean
console.log(typeOf(0)); // Number
console.log(typeOf("")); // String
console.log(typeOf(new Boolean(true))); // Boolean
console.log(typeOf(new Number(0))); // Number
console.log(typeOf(new String(""))); // String
Hope this article helped. To know more about the differences between primitives and wrapped objects read the following blog post: The Secret Life of JavaScript Primitives
typeof
check rather thaninstanceof
is that thetypeof
test will still work on strings from other frames or windows, or in a (admittedly contrived) situation where theString
constructor has been overwritten. – Rubinrubina