1.背景
我之前一直知道 typeof null 为 object ,但是一直没深究为什么?在查阅了相关的文档,汇总为以下文档
2.汇总解释
我们先来看 《JavaScript高级程序设计》 里面是怎么说的吧?
Null 类型同样只有一个值,即特殊值 null。逻辑上讲,null 值表示一个空对象指针,这也是给 typeof 传一个 null 会返回 "object" 的原因
这里我们就可以解释通了,null 其实是一个 空对象指针 ,所以 typeof 会检测 null 为 object
如果单纯是这样必然是不对的,是 空对象指针 就一定会被检测为 object 吗?
这其实就是一句总结,里面肯定有更加深层的原因,我看了一眼 ECMAScript 的文档,发现没有说这一点(可能是我没找到),倒是在 MDN 发现了解释
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 "object"
我来简单解释一遍,对象类型 表示为 0 ,null 在大部分机器上面都是 0x00...000 ,所以 null 为 0 ,所以 null 在 typeof 下 会被检测为 object
3.详细解释
这个解释已经能解答很多疑惑了,如果我们再往下面看一层呢?为什么对象类型为 0 ,null 为 0x00 ,typeof 底层分析类型是通过什么手段?以及这部分源码是什么样子的?
其实 JavaScript 的数据类型其实是通过 数据标签 + 数据值 的形式存在的,下面就是常见的数据标签
数据标签 | 类型 |
---|---|
000 | object |
1 | int |
010 | double |
100 | string |
110 | boolean |
在32位机器中,int 的 标签为 1 ,占了一位,那么后续的值为 2 ^ 30 ~2 ^ 30 - 1 (根据上图推算,现代JS早就改);其中 object 的标签为 000
这就是 JavaScript 的数据类型如何去做处理和区分的,当然还有2个特殊的值
- undefined 源码标记为 JSVAL_VOID
- null 源码标记为 JSVAL_NULL :是机器代码的 NULL****指针 。或者说,它是一个对象类型标记加上一个引用为零的组合,大部分机器都认定为 0x000
我们来看下面的 typeof 源码部分
- 发现没有 显式的判断 null****值 的标记,只有 undefined,object,number,string,boolean 的判断
- 再加上 null 在很多的机器中默认是 0x000 ,那么就会走 JSVAl_IS_OBJECT(v) 的逻辑,被认定为 object 类型
c
// 这是一个宏,它指定了函数的返回类型为 JSType,并且声明该函数是一个公共API
JS_PUBLIC_API(JSType)
JS_TypeOfValue(JSContext *cx, jsval v) {
JSType type = JSTYPE_VOID;
JSObject *obj;
JSObjectOps *ops;
JSClass *clasp;
// 这是一个宏,用于检查传入的 JSContext 是否有效
CHECK_REQUEST(cx);
if (JSVAL_IS_VOID(v)) {
type = JSTYPE_VOID;
} else if (JSVAL_IS_OBJECT(v)) {
// 如果 v 是对象类型,则检查它是否是函数对象,如果是函数对象则将 type 设置为 JSTYPE_FUNCTION
// 否则将其设置为 JSTYPE_OBJECT
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;
}
在 V8 Blog 对于 typeof null 为 object 的解释。我来简单解释一下:V8 Blog 认为 null 表示 no object value,所以输出 object 没问题
当然这有一股王婆卖瓜,自卖自夸的感觉了,毕竟是 JavaScript 最初设计的问题
4.总结
到这里继续深究下去已经没必要了,就是最初设计的缺陷导致的,当然这次的查询告诉我们对于高级语言的设计并不一定都是对的,如果想深究,也能看到 JavaScript 很多不合理的地方
参考文章
javascript - Why is typeof null "object"? - Stack Overflow
The story of a V8 performance cliff in React · V8
typeof - JavaScript | MDN (mozilla.org)