typeof
操作符唯一的目的就是检查数据类型
类型 | typeof结果 | |
---|---|---|
undefined | 基本类型 | 'undefined' |
Boolean | 基本类型 | 'boolean' |
Number | 基本类型 | 'number' |
String | 基本类型 | 'string' |
BigInt (ECMAScript 2020 新增) | 基本类型 | 'bigint' |
Symbol | 基本类型 | 'symbol' |
null | 基本类型 | 'object' |
Object(Object、Array、Map、Set等) | 引用类型 | 'object' |
Function | 引用类型 | 'function' |
在 JavaScript 中,typeof null是'object',它错误地表明null是一个对象(它不是,它是一个原始值)
“typeof null”错误是 JavaScript 第一个版本的残余。在这个版本中,值以 32 位为单位存储,它由一个小型标签(1-3 位)和值的实际数据组成。类型标签存储在单元的低位中。其中有五个:
- 000:对象。数据是对对象的引用。
- 1:整数。数据是一个 31 位有符号整数。
- 010:双倍。数据是对双浮点数的引用。
- 100:字符串。数据是对字符串的引用。
- 110:布尔值。数据是一个布尔值。
也就是说,最低位是任一位,那么类型标签只有一位长。或者它是零,那么类型标签的长度是三位,为四种类型提供两个额外的位。
两个值很特别:
- undefined ( JSVAL_VOID ) 是整数 -2^30 (整数范围之外的数字)。
- null ( JSVAL_NULL ) 是机器码空指针。或者:一个对象类型标签加上一个为零的引用。
现在应该很明显为什么typeof认为null是一个对象:它检查了它的类型标签,并且类型标签表示“对象”。以下是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; // undefined
} 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; // function
} else {
type = JSTYPE_OBJECT; //object
}
} else if (JSVAL_IS_NUMBER(v)) {
type = JSTYPE_NUMBER; //number
} else if (JSVAL_IS_STRING(v)) {
type = JSTYPE_STRING; //string
} else if (JSVAL_IS_BOOLEAN(v)) {
type = JSTYPE_BOOLEAN; //boolean
}
return type;
}
上述代码执行的步骤是:
- 在 (1) 处,引擎首先检查值v是否未定义(VOID)。此检查是通过使用 equals 比较值来执行的:
#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 的第一个版本的时间很少。
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于
null
代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null
也因此返回"object"
。(参考来源)
曾有一个 ECMAScript 的修复提案(通过选择性加入的方式),但被拒绝了。该提案会导致
typeof null === 'null'
。
Object.prototype.toString(扩展)
还有一个不错的判断类型的方法,就是 Object.prototype.toString ,我们可以利用这个方法来对一个变量的类型来进行比较准确的判断
Object.prototype.toString.call("abc"); // "[object String]"
Object.prototype.toString.call(100); // "[object Number]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call([1,2,3]); // "[object Array]"
Object.prototype.toString.call(/\w/); // "[object RegExp]"
参考:https://2ality.com/2013/10/typeof-null.html
https://www.pzijun.cn/blog/1/1.1.html#typeof
网友评论