typeof
操作符返回一个字符串,表示检测变量的数据类型。
用法:
typeof operand
typeof(operand)
举几个列子:
typeof 9007199254740991n // "bigint"
typeof null // "object"
typeof [] // "object"
typeof Symbol() // "symbol"
typeof new Function() // "function"
在这里有几个特别的地方,比如 typeof null
和 typeof array
都会返回 object
。
返回值
JS 中有八种数据类型(number
,string
,boolean
,null
,undefined
,symbol
,bigint
和 object
),typeof 的返回值也有八种。
"number"、"boolean"、"string"、"object"、"undefined"、"symbol"、"function"、"bigint"
-
由于历史原因,
typeof null
会返回object
,这是一个预计永远不会在 JS 中被修复的 bug。这就意味着不能使用typeof
来检查值为null
的类型。但是比较方便的是可以使用严格相等运算符(===)来检查。maybeNull === null
-
由于
typeof
检查函数类型都会返回function
,所以可以很简单的判断函数类型。 -
typeof array
返回object
,所以就出现了一个问题,如何能准确的确定变量是否为数组:一种方法是使用instanceof
,一种使用Array.isArray()
,一种是使用Object.prototype.toString.call(arr)
,一种是arr.constructor === Array
。 -
使用对象包装器
Number()
、String()
等创建的变量会返回object
。typeof new Number(12) // "object" typeof new String('str') // "object"
为什么 typeof null 是 object
这是一个无法修复的 bug,因为它会影响现有的代码。这个 bug 是第一个 JS 版本留下的问题,在早期的版本中,值被存在 32bit 单元中,由 1-3bits 类型标签和实际数据组成。类型标签存储在单元的较低位,有五种:
000
object,数据是对对象的引用1
int,数据是31位有符号整数010
double,数据是对双浮点数的引用100
string,数据是对字符串的引用110
boolean,数据是布尔值
也就是说,最低位是1的话,这个类型标签只有1位,如果最低位是0的话,那么类型标签有3位,为4种类型提供两个附加位。
有两个特殊的值:
undefined
一个超出整数范围的数字null
是机器代码 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)
: 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),则将其标记为一个函数,否则为对象。
(4) 然后检查数值,字符串,布尔类型。
总结
- 对于基本类型,除了
null
之外,均可以返回正确的结果 - 对于引用类型,除了
function
之外,一律返回object
类型 - 对于
null
,返回object
类型 - 对于
function
,返回function
类型