Many front-end developers may not bother to understand why typeof NULL is an Object. To learn more about the origin of this bug, see Dr. Axel Rauschmayer’s article on the history of “Typeof NULL”.

The original link: www.2ality.com/2013/10/typ…

I took a look at the C specification for Typeof, which has a better explanation for why typeof null results in ‘object’.

In JavaScript, the result of typeof NULL is ‘Object’, which incorrectly implies that NULL is an Object when in fact it is a primitive value. As I mentioned in my last article, this is a major BUG with JS. Unfortunately, it can’t be fixed because it would break the existing specification. Here’s the history of this bug.

The “typeof null” error has been around since the first version of JavaScripts. In this version, values are stored in 32-bit units, consisting of small labels (1-3 bits) and the actual data for the value. The type label is stored in the lower level of the cell. There are five:

  • 000: objectData is a reference to an object.
  • 1: intThe data is a 31 – bit signed integer.
  • 010: double. Data is a reference to a double floating point number.
  • 100: string. Data is a reference to a string.
  • 110: boolean. Data is Boolean.

That is, the least significant is 1, and then the type label is only 1 bit long, that is, int. Or the least significant is 0, then the type label is three bits long, providing two additional bits for the remaining four types.

But two values are special:

  • undefined(JSVAL_VOID) is an integer −2^30 (a number outside the integer range).
  • null(JSVAL_NULL) is a NULL pointer to machine code NULL, or an object label of type 0.

It should now be clear why Typeof considers NULL to be an object: it detects one of its type labels and returns “object”. Here is the typeof engine code:

 JS_PUBLIC_API(JSType)
    JS_TypeOfValue(JSContext *cx, jsval v)
    {
        JSType type = JSTYPE_VOID;
        JSObject *obj;
        JSObjectOps *ops;
        JSClass *clasp;

        CHECK_REQUEST(cx);
        if (JSVAL_IS_VOID(v)) {  / / (1)
            type = JSTYPE_VOID;
        } else if (JSVAL_IS_OBJECT(v)) {  / / (2)
            obj = JSVAL_TO_OBJECT(v);
            if (obj &&
                (ops = obj->map->ops,
                 ops == &js_ObjectOps
                 ? (clasp = OBJ_GET_CLASS(cx, obj),
                    clasp->call || clasp == &js_FunctionClass) / / (3, 4): ops->call ! =0)) {  / / (3)
                type = JSTYPE_FUNCTION;
            } else{ type = JSTYPE_OBJECT; }}else if (JSVAL_IS_NUMBER(v)) {
            type = JSTYPE_NUMBER;
        } else if (JSVAL_IS_STRING(v)) {
            type = JSTYPE_STRING;
        } else if (JSVAL_IS_BOOLEAN(v)) {
            type = JSTYPE_BOOLEAN;
        }
        return type;
    }
Copy the code

The above code performs the following steps:

  • (1) The engine first detects whether the value isundefinedVOID, it passes= =The comparison was made as follows:
#define JSVAL_IS_VOID(v)  ((v) == JSVAL_VOID)
Copy the code
  • The next (2) checks whether the value has an object Type. V is a function if it can be called with call (3) or if it has an internal attribute [[Class]] marked as a function (4). Otherwise, it is an object. This is the result generated by Typeof NULL.

  • Subsequent checks are for number, String, and Boolean, and not even null explicitly. This can be done by the following C language macros.

#define JSVAL_IS_NULL(v)  ((v) == JSVAL_NULL)`  
Copy the code

This may seem like an obvious bug, but don’t forget that the first version of JavaScript was completed in a fraction of the time, as you can see in the birth of JavaScript.

If you find this article helpful, you are welcomeMy GitHub blogLike and follow, thank you!