typeof操作符

​ 因为 ECMAScript 的类型系统是松散的,所以需要一种手段来确定任意变量的数据类型。typeof 操作符就是为此而生的。对一个值使用 typeof 操作符会返回下列字符串之一:

  • “undefined”表示值未定义;
  • “boolean”表示值为布尔值;
  • “string”表示值为字符串;
  • “number”表示值为数值;
  • “object”表示值为对象(而不是函数)或 null;
  • “function”表示值为函数;
  • “symbol”表示值为符号。

​ 下面是使用 typeof 操作符的例子:

let message = "some string";
console.log(typeof message);
console.log(typeof message);
console.log(typeof 95);
// "string"
// "string"
// "number"

​ 在这个例子中,我们把一个变量(message)和一个数值字面量传给了 typeof 操作符。注意,因 为 typeof 是一个操作符而不是函数,所以不需要参数(但可以使用参数)。

​ 注意 typeof 在某些情况下返回的结果可能会让人费解,但技术上讲还是正确的。比如,调用 typeof null 返回的是”object”。这是因为特殊值 null 被认为是一个对空对象的引用。

注意 严格来讲,函数在 ECMAScript 中被认为是对象,并不代表一种数据类型。可是,函数也有自己特殊的属性。为此,就有必要通过 typeof 操作符来区分函数和其他对象

Undefined类型

​ Undefined 类型只有一个值,就是特殊值 undefined。当使用 var 或 let 声明了变量没有初始化时,就相当于给变量赋予undefined 值:

let message;
console.log(message == undefined); // true

​ 在这个例子中,变量 message 在声明的时候并未初始化。而在比较它和 undefined 的字面值时, 两者是相等的。这个例子等同于如下示例:

let message = undefined;
console.log(message == undefined); // true

​ 这里,变量 message 显式地以 undefined 来初始化。但这是不必要的,因为默认情况下,任何未经初始化的变量都会取得 undefined 值。

注意 一般来说,永远不用显式地给某个变量设置 undefined 值。字面值 undefined 主要用于比较,而且在 ECMA-262 第 3 版之前是不存在的。增加这个特殊值的目的就是为 了正式明确空对象指针(null)和未初始化变量的区别。

​ 注意,包含 undefined 值的变量跟未定义变量是有区别的。请看下面的例子:

let message; // 这个变量被声明了,只是值为undefined
// 确保没有声明过这个变量
// let age
console.log(message); // "undefined"
console.log(age); // 报错

​ 在上面的例子中,第一个 console.log 会指出变量 message 的值,即”undefined”。而第二个 console.log 要输出一个未声明的变量 age 的值,因此会导致报错。对未声明的变量,只能执行一个有用的操作,就是对它调用 typeof。(对未声明的变量调用 delete 也不会报错,但这个操作没什么用, 实际上在严格模式下会抛出错误。)

​ 在对未初始化的变量调用 typeof 时,返回的结果是”undefined”,但对未声明的变量调用它时, 返回的结果还是”undefined”,这就有点让人看不懂了。比如下面的例子:

let message; // 这个变量被声明了,只是值为undefined
// 确保没有声明过这个变量
// let age
console.log(typeof message); // "undefined"
console.log(typeof age); // "undefined"

注意 即使未初始化的变量会被自动赋予 undefined 值,但我们仍然建议在声明变量的 同时进行初始化。这样,当 typeof 返回”undefined”时,你就会知道那是因为给定的变量尚未声明,而不是声明了但未初始化

​ undefined 是一个假值。因此,如果需要,可以用更简洁的方式检测它。不过要记住,也有很多其他可能的值同样是假值。所以一定要明确自己想检测的就是 undefined 这个字面值,而不仅仅是假值

let message; // 这个变量被声明了,只是值为undefined
// age 没有声明
if (message) {
  // 这个块不会执行
}
if (!message) {
  // 这个块会执行
}
if (age) {
  // 这里会报错
}

Null类型

​ Null 类型同样只有一个值,即特殊值 null。逻辑上讲,null 值表示一个空对象指针,这也是给 typeof 传一个 null 会返回”object”的原因:

let car = null;
console.log(typeof car); // "object"

​ 在定义将来要保存对象值的变量时,建议使用 null 来初始化,不要使用其他值。这样,只要检查这个变量的值是不是 null 就可以知道这个变量是否在后来被重新赋予了一个对象的引用,比如:

if (car != null) {
  // car 是一个对象的引用
}

​ undefined 值是由 null 值派生而来的,因此 ECMA-262 将它们定义为表面上相等,如下面的例 子所示:

console.log(null == undefined); // true
console.log(null === undefined); // false

​ 用等于操作符(==)比较 null 和 undefined 始终返回 true。但要注意,这个操作符会为了比较而转换它的操作数(本章后面将详细介绍)。

​ 即使 null 和 undefined 有关系,它们的用途也是完全不一样的。如前所述,永远不必显式地将变量值设置为 undefined。但 null 不是这样的。任何时候,只要变量要保存对象,而当时又没有那个对象可保存,就要用 null 来填充该变量。这样就可以保持 null 是空对象指针语义,并进一步将其 与 undefined 区分开来。

​ null 是一个假值。因此,如果需要,可以用更简洁的方式检测它。不过要记住,也有很多其他可能的值同样是假值。所以一定要明确自己想检测的就是 null 这个字面值,而不仅仅是假值。

let message = null;
let age;
if (message) {
  // 这个块不会执行
}
if (!message) {
  // 这个块会执行
}
if (age) {
  // 这个块不会执行
}
if (!age) {
  // 这个块会执行
}