你真的知道typeof null的結果為什麼是‘object‘嗎?

_Fatman發表於2021-02-19

到目前為止,ECMAScript 標準中定義了8種資料型別,它們分別是Undefined、Null、Number、Boolean、String、Symbol、BigInt、Object。
為了判斷變數的資料型別,JavaScript還提供了typeof操作符
資料型別中的值通過typeof操作符操作過後輸出的值對應表格:

資料型別 結果
Undefined undefined 'undefined'
Null null 'object'
Number 1、1.0、NaN、Infinity 'number'
Boolean true、false 'boolean'
String '' 、'abc' 'string'
Symbol Symbol()、Symbol('123') 'symbol'
BigInt 0n、1n 'bigint'
Object {}、[] 'object'
Object function(){} 'function'

通過觀察,我們可以發現一個問題——typeof操作符錯誤的將一個原始型別值null判斷為object

typeof null === 'object'//true

這將導致typeof x === 'object'時,x還有可能是null

這個問題的產生可以追溯到JavaScript的第一個版本[1],在這個版本中,單個值在棧中佔用32位的儲存單元,而這32位的儲存單元又可以劃分為型別標籤(1-3位)和實際資料,型別標籤儲存於低位中,具體可以分成5種:

(1)
圖片來自window10計算器程式設計師模式
如圖[2],當第0位、第1位和第2位皆為0時,typeof判斷型別為'object';

(2)
圖片來自window10計算器程式設計師模式
如圖[2:1],當第0位為1時,typeof判斷型別為'number(整數)';

(3)
在這裡插入圖片描述
如圖[2:2],當第0位與第2位皆為0,而第1位為1時,typeof判斷型別為'number(浮點數)';

(4)
在這裡插入圖片描述
如圖[2:3],當第0位與第1位皆為0,而第2位為1時,typeof判斷型別為'string';

(5)
在這裡插入圖片描述
如圖[2:4],當第1位與第2位皆為1,而第0位為0時,typeof判斷型別為'boolean';

此外還有兩種特殊情況:
undefined:整數−2^30 (整數範圍之外的數字)
null:第0位到第31位皆為0(正好滿足當第0位、第1位和第2位皆為0時,typeof判斷型別為'object'的條件)

下面的程式碼更好的說明了這個問題(來源):

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)) {
            type = JSTYPE_VOID;
        } else if (JSVAL_IS_OBJECT(v)) {
            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) 
                 : ops->call != 0)) { 
                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;
    }

正因如此,導致typeof null === 'object'為true。


  1. 此時還沒有 Symbol、BigInt,故不在討論範圍內; ↩︎

  2. 圖片來自window10計算器程式設計師模式; ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

相關文章