typeof
======

**`typeof`** 运算符返回一个字符串，表示操作数的类型。

尝试一下
----

语法
--


```js
typeof operand
```

### 参数

`operand`

表示要返回类型的对象或基本类型的表达式。

描述
--

下表总结了 `typeof` 可能的返回值。有关类型和基本类型的更多信息，可查看 JavaScript 数据结构 页面。

| 类型 | 结果 |
| --- | --- |
| Undefined | `"undefined"` |
| Null | `"object"`（原因） |
| Boolean | `"boolean"` |
| Number | `"number"` |
| BigInt | `"bigint"` |
| String | `"string"` |
| Symbol | `"symbol"` |
| Function（在 ECMA-262 中实现 [[Call]]；classes也是函数) | `"function"` |
| 其他任何对象 | `"object"` |

这个值列表是详尽的。没有符合规范的引擎曾被报告过产生（或历史上产生过）除列出的值之外的值。在规范删除 `typeof` 为不可调用的非标准外来对象返回实现定义的字符串的行为之前，旧的 Internet Explorer 是已知的唯一一个实现额外返回值的浏览器。

示例
--

### 基本用法


```js
// 数值
typeof 37 === "number";
typeof 3.14 === "number";
typeof 42 === "number";
typeof Math.LN2 === "number";
typeof Infinity === "number";
typeof NaN === "number"; // 尽管它是 "Not-A-Number" (非数值) 的缩写
typeof Number(1) === "number"; // Number 会尝试把参数解析成数值
typeof Number("shoe") === "number"; // 包括不能将类型强制转换为数字的值

typeof 42n === "bigint";

// 字符串
typeof "" === "string";
typeof "bla" === "string";
typeof `template literal` === "string";
typeof "1" === "string"; // 注意内容为数字的字符串仍是字符串
typeof typeof 1 === "string"; // typeof 总是返回一个字符串
typeof String(1) === "string"; // String 将任意值转换为字符串，比 toString 更安全

// 布尔值
typeof true === "boolean";
typeof false === "boolean";
typeof Boolean(1) === "boolean"; // Boolean() 会基于参数是真值还是虚值进行转换
typeof !!1 === "boolean"; // 两次调用 !（逻辑非）运算符相当于 Boolean()

// Symbols
typeof Symbol() === "symbol";
typeof Symbol("foo") === "symbol";
typeof Symbol.iterator === "symbol";

// Undefined
typeof undefined === "undefined";
typeof declaredButUndefinedVariable === "undefined";
typeof undeclaredVariable === "undefined";

// 对象
typeof { a: 1 } === "object";

// 使用 Array.isArray 或者 Object.prototype.toString.call
// 区分数组和普通对象
typeof [1, 2, 4] === "object";

typeof new Date() === "object";
typeof /regex/ === "object";

// 下面的例子令人迷惑，非常危险，没有用处。避免使用它们。
typeof new Boolean(true) === "object";
typeof new Number(1) === "object";
typeof new String("abc") === "object";

// 函数
typeof function () {} === "function";
typeof class C {} === "function";
typeof Math.sin === "function";
```

### typeof null


```js
// JavaScript 诞生以来便如此
typeof null === "object";
```


在 JavaScript 最初的实现中，JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 `null` 代表的是空指针（大多数平台下值为 0x00），因此，null 的类型标签是 0，`typeof null` 也因此返回 `"object"`。（参考来源）

曾有一个 ECMAScript 的修复提案（通过选择性加入的方式），但被拒绝了。该提案会导致 `typeof null === 'null'`。

### 使用 new 操作符

所有使用 `new` 调用的构造函数都将返回非基本类型（`"object"` 或 `"function"`）。大多数返回对象，但值得注意的例外是 `Function`，它返回一个函数。


```js
const str = new String("String");
const num = new Number(100);

typeof str; // "object"
typeof num; // "object"

const func = new Function();

typeof func; // "function"
```

### 语法中需要圆括号

`typeof` 操作符的优先级高于加法（`+`）等二进制操作符。因此，需要用括号来计算加法结果的类型。


```js
// 括号有无将决定表达式的类型。
const someData = 99;

typeof someData + " Wisen"; // "number Wisen"
typeof (someData + " Wisen"); // "string"
```

### 与未声明和未初始化变量的交互

`typeof` 通常总是保证为它提供的任何操作数返回一个字符串。即使使用未声明的标识符，`typeof` 也会返回 `"undefined"`，而不是抛出错误。


```js
typeof undeclaredVariable; // "undefined"
```


但在加入了块级作用域的 let 和 const 之后，在其被声明之前对块中的 `let` 和 `const` 变量使用 `typeof` 会抛出一个 ReferenceError。块作用域变量在块的头部处于“暂存死区”，直至其被初始化，在这期间，访问变量将会引发错误。


```js
typeof newLetVariable; // ReferenceError
typeof newConstVariable; // ReferenceError
typeof newClass; // ReferenceError

let newLetVariable;
const newConstVariable = "hello";
class newClass {}
```

### document.all 的异常行为

当前所有浏览器都公开了一个类型为 `undefined` 的非标准宿主对象 `Document.All`。


```js
typeof document.all === "undefined";
```


虽然 `document.all` 也是假值，与 `undefined` 非严格相等，但它不是 `undefined`。在 Web 标准中，`document.all` 具有 `"undefined"` 类型的情况被归类为“故意违反”原始 ECMAScript Web 兼容性标准。

### 获取具体类型的自定义方法

`typeof` 是非常有用的，但它不像需要的那样万能。例如，`typeof []` 是 `"object"`，以及 `typeof new Date()`、`typeof /abc/` 等。

为了更明确地检查类型，这里我们提供了一个自定义的 `type(value)` 函数，它主要模仿 `typeof` 的行为，但对于非基本类型（即对象和函数），它在可能的情况下返回更详细的类型名。


```js
function type(value) {
  if (value === null) {
    return "null";
  }
  const baseType = typeof value;
  // 基本类型
  if (!["object", "function"].includes(baseType)) {
    return baseType;
  }

  // Symbol.toStringTag 通常指定对象类的“display name”
  // 它在 Object.prototype.toString() 中使用。
  const tag = value[Symbol.toStringTag];
  if (typeof tag === "string") {
    return tag;
  }

  // 如果它是一个函数，其源代码以 "class" 关键字开头
  if (
    baseType === "function" &&
    Function.prototype.toString.call(value).startsWith("class")
  ) {
    return "class";
  }

  // 构造函数的名称；例如 `Array`、`GeneratorFunction`、`Number`、`String`、`Boolean` 或 `MyCustomClass`
  const className = value.constructor.name;
  if (typeof className === "string" && className !== "") {
    return className;
  }

  // 在这一点上，没有合适的方法来获取值的类型，因此我们使用基本实现。
  return baseType;
}
```


要检查可能不存在的变量，否则会抛出 `ReferenceError`，请使用 `typeof nonExistentVar === 'undefined'`，因为自定义代码无法模仿这种行为。

规范
--

| Specification |
| --- |
| ECMAScript Language Specification # sec-typeof-operator |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* `instanceof`
* `document.all` willful violation of the standard