【譯】談談「typeof null爲object」這一bug的由來

不少前端初級開發者也許並不深究typeof null爲什麼爲Object?想更深地瞭解這一bug的由來,能夠參閱Dr. Axel Rauschmayer關於"typeof null"的歷史這篇文章。javascript

原文連接:www.2ality.com/2013/10/typ…html

我看了下C語言關於typeof的規範,它對於typeof null爲什麼結果是’object’有更好的解釋。前端

在JavaScript中,typeof null的結果是'Object',它錯誤地暗示null是一個對象,實際上它是一個原始值。我在上一篇文章也提到了這是JS的一大bug,不幸的是這並不能解決,由於這將破壞現有規範,接下來解釋下這個bug的歷史。java

typeof null」的錯誤從JavaScripts第一個版本開始就已經存在了。在這個版本,值以32位爲單位存儲,由小型標籤(1-3位)和值的實際數據組成。類型標籤存儲在單元的低位中。 其中有五種:git

  • 000: object. 數據是對象的引用。
  • 1: int. 數據是31位有符號整數。
  • 010: double. 數據是對雙浮點數的引用。
  • 100: string. 數據是對字符串的引用。
  • 110: boolean. 數據是布爾值。

也就是說,最低位是1,而後類型標籤只有1位長,即int型。 或者最低位爲0,那麼類型標籤的長度爲3位,爲其他4種類型提供了兩個附加位。github

但有2個值是特殊的:函數

  • undefined(JSVAL_VOID)是整數−2^30(整數範圍以外的數字)。
  • null(JSVAL_NULL) 爲機器碼NULL的空指針,或者說:爲0的object類型標籤。

如今應該明白爲何typeof認爲null是一個對象:它檢測一個他的類型標籤而且返回」object」。 如下是typeof的引擎代碼:ui

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;
    }
複製代碼

上述代碼執行的步驟以下:spa

  • (1)引擎首先檢測值是不是undefined(VOID),它經過==作了這樣的比較:
#define JSVAL_IS_VOID(v) ((v) == JSVAL_VOID)
複製代碼
  • 下一個(2)是檢測該值是否具備object type。若是它可以使用call被調用(3)或其存在內部屬性[[Class]]標記爲函數(4),則v是函數。 不然,它是一個對象。 這是由typeof null生成的結果。指針

  • 後續檢查是針對numberstringboolean,甚至沒有明確檢查null。這能夠由如下C語言宏執行。

#define JSVAL_IS_NULL(v) ((v) == JSVAL_NULL)` 
複製代碼

這看似是一個很是明顯的bug,但不要忘記,第一個版本的JavaScript完成只用了極少的時間,具體能夠看看JavaScript的誕生

若是以爲文章對你有些許幫助,歡迎在個人GitHub博客點贊和關注,感激涕零!

相關文章
相關標籤/搜索