"What's the typeof null?", and other confusing JavaScript Types
The typeof
operator in JavaScript evaluates and returns a string with the data type of an operand. For example, to find the type of 123
, we would write -
typeof 123
This will return a string with the type of 123
, which, in this case, will be "number". In addition to "number", the typeof
operator can return one of 6 potential results -
typeof 123 // "number"
typeof "abc" // "string"
typeof true // "boolean"
typeof {a: 1} // "object"
typeof function foo() {} // "function"
typeof undefined // "undefined"
typeof Symbol('foo') // "symbol"
In the above examples, it's pretty straightforward what the type of the operands will be. However, there are a few cases where it is unclear or misunderstood what the type of the operand should be.
What's the typeof typeof 123
? #
typeof typeof 123 // "string"
What is the type of a typeof
expression? Well, the typeof
operator always returns a string with the type of the operand passed to it. If the resultant type of the expression is, for example, a number, what will be returned is "number"
. This means that, regardless of resultant type, the type of a typeof [any operand]
, will always be a string.
What's the typeof NaN
? #
typeof NaN // "number"
The type of NaN
, which stands for Not a Number is, surprisingly, a number. The reason for this is, in computing, NaN
is actually technically a numeric data type. However, it is a numeric data type whose value cannot be represented using actual numbers. So, the name "Not a Number", doesn't mean that the value is not numeric. It instead means that the value cannot be expressed with numbers.
This also explains why not all NaN
values are equal. For example -
const NaN1 = 2 * "abc";
const NaN2 = 2 * "abc";
NaN1 === NaN2 // false
Those two NaN
values are not equal because they are not necessarily the same unrepresentable number.
What's the typeof [1,2,3]
? #
typeof [1,2,3] // "object"
The typeof
an array is an object. In JavaScript, arrays are technically objects; just with special behaviours and abilities. For example, arrays have a Array.prototype.length
property, which will return the number of elements in the array. Arrays also have special methods, e.g. Array.prototype.push()
or Array.prototype.unshift()
(See JavaScript Array Methods - Mutator Methods).
To differentiate an Array object from an Object object, we can use the Array.isArray()
method.
Array.isArray( [1,2,3] ) // true
Array.isArray( { a: 1 } ) // false
What's the typeof null
? #
typeof null // "object"
The null
value is technically a primitive, the way "object" or "number" are primitives. This would typically mean that the type of null should also be "null". However, this is not the case because of a peculiarity with the way JavaScript was first defined.
In the first implementation of JavaScript, values were represented in two parts - a type tag and the actual value. There were 5 type tags that could be used, and the tag for referencing an object was 0
. The null
value, however, was represented as the NULL
pointer, which was 0x00
for most platforms. As a result of this similarity, null has the 0
type tag, which corresponds to an object.
What's the typeof class Foo {}
? #
typeof class Foo {} // "function"
Finally, we have Classes. Classes were introduced in ES2015 (ES6) as a better syntax for prototype-based inheritance. Before Classes, to make an inheritable object, we would have to use a function.
function Dog() { }
Dog.prototype.bark = function() {
alert("woof!");
}
const snoopy = new Dog();
snoopy.bark() // alert("woof!")
With Classes, we can create the same object this way -
class Dog {
bark() {
alert("woof!");
}
}
const snoopy = new Dog();
snoopy.bark() // alert("woof!")
However, Classes have always just been a syntactical wrapper around the function method. The same function is actually being created, but just with the author writing it in a different, cleaner way. This is why the typeof
a Class, is still just a Function.