在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 会使程序过于复杂。