你真的知道typeof null的结果为什么是‘object‘吗?

到目前为止,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计算器程序员模式; ↩︎ ↩︎ ↩︎ ↩︎ ↩︎