Why is typeof null an object in Javascript? published: 10th December 2024

All values in JS are either primitives or objects.

Primitives

  • Undefined
  • Null
  • Boolean
  • Number
  • String
  • BigInt
  • Symbol

Primitives are immutable, you cannot add properties to them.
> var str = "xyz";
> str.foo = "abc"; // try to add property "foo"
> str.foo // no change undefined

Primitives are compared by value, they are equal if they hold the same value
> "xyz" === "xyz";
true

Objects: all non-primitive values are objects and they are mutable.
> var obj = {};
> obj.foo = "abc"; // add property "foo"
abc
> obj.foo // "foo" has been added
abc

Objects are compared by reference. Two objects are considered equal only if they are in fact the same object.
> {} === {};
false
> var obj = {};
> obj === obj
true

To find the type of a variable JS provides the operator typeof which returns a string indicating the type of the operand's value.
> console.log(typeof 10); // output: "number"
> console.log(typeof 'abc'); // output: "string"
> console.log(typeof false); // output: "boolean"
> console.log(typeof undeclaredVariable); // output: "undefined"

Ok so let's look at what happens when we check the typeof null
> console.log(typeof null); // output: "object"

wat meme

hhhmmm something doesn't look right, how can a primitive value have a type of non-primitive value? What kind of bug is this in JS? This quirky JS behaviour comes from its early implementation where the values were stored in 32 bit units and the type information was encoded using a bit level approach where the type value could be quickly computed by looking at the lower bits of a 32 bit memory unit. There were five of them:

  • 000: data is reference to an object
  • 001: data is 31 bit signed integer
  • 010: data is reference to a floating point number
  • 100: data is a reference to string
  • 110: data is a boolean

If the lowest bit (the rightmost bit) is 1 the tag is 1 bit long. If the lowest bit is 0 the type tag is 3 bits long which provides two additional bits for four types. Two values were special and differed in implementation: undefined (JSVAL_VOID) the integer -230 which is -1073741824 (a number outside the integer range) and null (JSVAL_NULL) the machine code NULL pointer or an object type tag plus a reference that is zero. The system examined the type tag for null and rightfully said it's an "object". Remember JS was created as a prototype in 10 days by Brendan Eich so fore sighting such a bug was not really possible.