Null and typeof

The typeof operator can be a little counter-intuitive. However, regardless of the confusion it may cause, the way it works is extremely straightforward: return the type string of a given reference according to the table specified in ECMA-262:

Implementation

The actual implementation varies depending on which engine you are running. The V8 (behind Chrome and Node.js) implementation of the typeof operator (written in C++), is as follows (I've added a few comments for clarification):

// Returns the type string of a value; see ECMA-262, 11.4.3
RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
  NoHandleAllocation ha;

  Object* obj = args[0];
  if (obj->IsNumber()) return isolate->heap()->number_symbol();
  HeapObject* heap_obj = HeapObject::cast(obj);

  // typeof an undetectable object is 'undefined'
  if (heap_obj->map()->is_undetectable()) {
    return isolate->heap()->undefined_symbol();
  }

  InstanceType instance_type = heap_obj->map()->instance_type();
  if (instance_type < FIRST_NONSTRING_TYPE) {
    // return "string"
    return isolate->heap()->string_symbol();
  }

  switch (instance_type) {
    // oddbal types: true, false, null, undefined
    case ODDBALL_TYPE:
      // true, false
      if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
        // return "boolean"
        return isolate->heap()->boolean_symbol();
      }
      // null
      if (heap_obj->IsNull()) {
        return FLAG_harmony_typeof
            // return "null"
            ? isolate->heap()->null_symbol()
            // return "object"
            : isolate->heap()->object_symbol();
      }
      ASSERT(heap_obj->IsUndefined());
      // return "undefined"
      return isolate->heap()->undefined_symbol();
    case JS_FUNCTION_TYPE:
    case JS_FUNCTION_PROXY_TYPE:
      // return "function"
      return isolate->heap()->function_symbol();
    default:
      // For any kind of object not handled above, the spec rule for
      // host objects gives that it is okay to return "object"
      return isolate->heap()->object_symbol();
  }
}

Why does typeof null return "object"?

// What's happening here?
typeof null === "object"; // true

The answer might disappoint some, but the truth is simply because the table above says to do so.

The reasoning behind this is that null, in contrast with undefined, was (and still is) often used where objects appear. In other words, null is often used to signify an empty reference to an object. When Brendan Eich created JavaScript, he followed the same paradigm, and it made sense (arguably) to return "object". In fact, the ECMAScript specification defines null as the primitive value that represents the intentional absence of any object value (ECMA-262, 11.4.11).

There have been discussions in the ECMAScript working group (between Brendan Eich, Douglas Crockford, and a few other other individuals) proposing the following change:

typeof null === "null"; // true

However, as Douglas Crockford pointed out, "I think it is too late to fix typeof. The change proposed for typeof null will break existing code." By "existing code" he means many incorrect implementations of type checks on the web, such as:

// This is extremely bad
function isNull(a) {
  return typeof a == 'object' && !a;
}

Because of this, it was decided to leave typeof alone.

Back to V8

If you actually read each line of the V8 typeof operator implementation in RUNTIMEFUNCTION above, you might have noticed that FLAGharmony_typeof check:

// null
if (heap_obj->IsNull()) {
  return FLAG_harmony_typeof
      // return "null"
      ? isolate->heap()->null_symbol()
      // return "object"
      : isolate->heap()->object_symbol();
}

Assuming you have the V8 Canary build on your machine, you can run it with the --harmony-typeof flag, which would essentially set the FLAGharmonytypeof to true. Now, any typeof null check is going to return "null".