為毛 "typeof null" 的結果為 "object" ?

茄子發表於2019-06-17

翻譯 & 改編自 http://2ality.com/2013/10/typeof-null.html

在 JavaScript 中typeof null 的結果為 "object",這是從 JavaScript 的第一版遺留至今的一個 bug。並且,因為影響太廣已經永遠無法修復這個 bug 了。我們來挖一挖墳,看看這個 bug 是怎麼來的。

在第一版的 JavaScript 中,變數的值被設計儲存在一個 32 位的記憶體單元中。該單元包含一個 1 或 3 位的型別標誌,和實際資料的值。型別標誌儲存在單元的最後。包括以下五種情況:

  • 000:object,資料為物件的引用
  • 1:int,資料為 31 位的有符號整型
  • 010:double,資料為一個雙精度浮點數的引用
  • 100:string,資料為一個字串的引用
  • 110:boolean,資料為布林型別的值

除此之外,還有兩種特殊情況:

  • undefined 負的 2 的 30 次方(超出當時整型取值範圍的一個數)
  • null 空指標

顯而易見,null 的儲存單元最後三位和 object 一樣是 000。然後讓我們再看一下 typeof實現

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;
    }

程式碼的大致執行步驟:

  • 在步驟(1)判斷值 v 是否為 undefined(VOID),這個檢查通過下面的比較來判斷:
    #define JSVAL_IS_VOID(v)  ((v) == JSVAL_VOID)
  • 接下來,在步驟(2)判斷值是否包含 object 標誌,並且通過(3)判斷值是否可以呼叫,或者(4)判斷值是否在屬性 [[Class]] 中被標記為函式,來判斷值為函式,否則為物件。
  • 接下來的步驟,依次判斷是否為 numberstringboolean

在步驟(2)中 null 會被判斷為 object,其實避免這個 bug 的方式很簡單,在步驟(2)之前顯示的檢查值是否為 null

#define JSVAL_IS_NULL(v)  ((v) == JSVAL_NULL)

考慮 JavaScript 之父在非常緊迫的時間裡完成了這門語言的設計與開發,我們就原諒他吧 :pensive:

Night gathers, and now my watch begins.

相關文章