内建类型

JavaScript 定义了七种内建类型:

  • null
  • undefined
  • boolean
  • number
  • string
  • object
  • symbol — 在 ES6 中被加入的!

注意: 除了 object 所有这些类型都被称为“基本类型(primitives)”。

typeof 操作符可以检测给定值的类型,而且总是返回七种字符串值中的一种 — 令人吃惊的是,对于我们刚刚列出的七中内建类型,它没有一个恰好的一对一匹配。

  1. typeof undefined === "undefined"; // true
  2. typeof true === "boolean"; // true
  3. typeof 42 === "number"; // true
  4. typeof "42" === "string"; // true
  5. typeof { life: 42 } === "object"; // true
  6. // 在 ES6 中被加入的!
  7. typeof Symbol() === "symbol"; // true

如上所示,这六种列出来的类型拥有相应类型的值,并返回一个与类型名称相同的字符串值。Symbol 是 ES6 的新数据类型,我们将在第三章中讨论它。

正如你可能已经注意到的,我在上面的列表中剔除了 null。它是 特殊的 — 特殊在它与 typeof 操作符组合时是有 bug 的。

  1. typeof null === "object"; // true

要是它返回 "null" 就好了(而且是正确的!),但是这个原有的 bug 已经存在了近二十年,而且好像永远也不会被修复了,因为有太多已经存在的 web 的内容依存着这个 bug 的行为,“修复”这个 bug 将会 制造 更多的“bug”并毁掉许多 web 软件。

如果你想要使用 null 类型来测试 null 值,你需要一个复合条件:

  1. var a = null;
  2. (!a && typeof a === "object"); // true

null 是唯一一个“falsy”(也叫类 false;见第四章),但是在 typeof 检查中返回 "object" 的基本类型。

那么 typeof 可以返回的第七种字符串值是什么?

  1. typeof function a(){ /* .. */ } === "function"; // true

很容易认为在 JS 中 function 是一种顶层的内建类型,特别是看到 typeof 操作符的这种行为时。然而,如果你阅读语言规范,你会看到它实际上是对象(object)的“子类型”。特别地,一个函数(function)被称为“可调用对象” —— 一个拥有 [[Call]] 内部属性、允许被调用的对象。

函数实际上是对象这一事实十分有用。最重要的是,它们可以拥有属性。例如:

  1. function a(b,c) {
  2. /* .. */
  3. }

这个函数对象拥有一个 length 属性,它被设置为函数被声明时的形式参数的数量。

  1. a.length; // 2

因为你使用了两个正式命名的参数(bc)声明了函数,所以“函数的长度”是 2

那么数组呢?它们是 JS 原生的,所以它们是一个特殊的类型咯?

  1. typeof [1,2,3] === "object"; // true

不,它们仅仅是对象。考虑它们的最恰当的方法是,也将它们认为是对象的“子类型”(见第三章),带有被数字索引的附加性质(与仅仅使用字符串键的普通对象相反),并维护着一个自动更新的 .length 属性。