【译】谈谈“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博客点赞和关注,感激涕零!

相关文章
相关标签/搜索