为什么JavaScript里面typeof(null)的值是"object"?

在JavaScript中,typeof null是'object',它不正确地表明null是一个对象,这是一个错误,不幸的是无法修复,因为它会破坏现有的代码。我们来探讨这个bug的历史。

“typeof null”错误是JavaScript第一个版本的补遗。在这个版本中,值以32位为单位存储,其中包含一个小型标记(1-3位)和实际的数据值。类型标签存储在单元的低位中。其中有五个:

000:object        数据是对对象的引用。

1:int        数据是一个31位有符号整数。

010:double        数据是对双浮点数的引用。

100:string        数据是对字符串的引用。

110:boolean        数据是一个布尔值。

也就是说,最低位是一个,然后类型标签只有一个位长。或者它是零,那么类型标签的长度是三位,为四种类型提供两个附加位。

两个值是特殊的:

未定义(JSVAL_VOID)是整数-2 30(整数范围之外的数)。

null(JSVAL_NULL)是机器码空指针。或者:一个对象类型标记加上一个为零的引用。

现在应该很明显,为什么typeof认为null是一个对象:它检查了它的类型标签,而类型标签说了“object”。以下是typeof的引擎代码。

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;

    }

上述代码执行的步骤是:

在(1)处,引擎首先检查值v是否是未定义的(VOID)。该检查通过等于比较值来执行:

    #define JSVAL_IS_VOID(v)((v)== JSVAL_VOID)

下一个检查(2)是该值是否具有对象标签。如果它另外是可调用的(3)或其内部属性[[Class]]将其标记为函数(4),则v是函数。否则,它是一个对象。这是由typeof null产生的结果。

随后的检查是针对数字,字符串和布尔值。甚至没有对null进行明确的检查,这可以由以下C宏执行。

    #define JSVAL_IS_NULL(v)((v)== JSVAL_NULL)

这可能看起来像一个非常明显的错误,但不要忘记,完成JavaScript的第一个版本的时间非常短。

 

 

 在程序中如何判断变量是否为null。

    以下是不正确的方法: 

1、var exp = null;

    if (exp == null)

    {

        alert("is null");

    }

    exp 为 undefined 时,也会得到与 null 相同的结果,虽然 null 和 undefined 不一样。

    注意:要同时判断 null 和 undefined 时可使用本法。

2、var exp = null;

    if (!exp)

    {

        alert("is null");

    }

    如果 exp 为 undefined,或数字零,或 false,也会得到与 null 相同的结果,虽然 null 和二者不一样。

    注意:要同时判断 null、undefined、数字零、false 时可使用本法。

3、var exp = null;

    if (typeof exp == "null")

    {

        alert("is null");

    }

    为了向下兼容,exp 为 null 时,typeof null 总返回 object,所以不能这样判断。

4、var exp = null;

    if (isNull(exp))

    {

        alert("is null");

    }

    VBScript 中有 IsNull 这个函数,但 JavaScript 中没有。

--------------------------------------------------------------------------------

    以下是正确的方法: 

1、var exp = null;

    if (!exp && typeof exp != "undefined" && exp != 0)

    {

        alert("is null");

    }

    typeof exp != "undefined" 排除了 undefined; 

    exp != 0 排除了数字零和 false。

    更简单的正确的方法:

 

2、var exp = null;

    if (exp === null)

    {

        alert("is null");

    }

--------------------------------------------------------------------------------

尽管如此,我们在 DOM 应用中,一般只需要用 (!exp) 来判断就可以了,因为 DOM 应用中,可能返回 null,可能返回 undefined,如果具体判断 null 还是 undefined 会使程序过于复杂。



作者:Gerhard_杨光辉
链接:https://www.jianshu.com/p/7d3b7027d970
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值