内建类型
JavaScript 定义了七种内建类型:
null
undefined
boolean
number
string
object
symbol
— 在 ES6 中被加入的!
注意: 除了 object
所有这些类型都被称为“基本类型(primitives)”。
typeof
操作符可以检测给定值的类型,而且总是返回七种字符串值中的一种 — 令人吃惊的是,对于我们刚刚列出的七中内建类型,它没有一个恰好的一对一匹配。
typeof undefined === "undefined"; // true
typeof true === "boolean"; // true
typeof 42 === "number"; // true
typeof "42" === "string"; // true
typeof { life: 42 } === "object"; // true
// 在 ES6 中被加入的!
typeof Symbol() === "symbol"; // true
如上所示,这六种列出来的类型拥有相应类型的值,并返回一个与类型名称相同的字符串值。Symbol
是 ES6 的新数据类型,我们将在第三章中讨论它。
正如你可能已经注意到的,我在上面的列表中剔除了 null
。它是 特殊的 — 特殊在它与 typeof
操作符组合时是有 bug 的。
typeof null === "object"; // true
要是它返回 "null"
就好了(而且是正确的!),但是这个原有的 bug 已经存在了近二十年,而且好像永远也不会被修复了,因为有太多已经存在的 web 的内容依存着这个 bug 的行为,“修复”这个 bug 将会 制造 更多的“bug”并毁掉许多 web 软件。
如果你想要使用 null
类型来测试 null
值,你需要一个复合条件:
var a = null;
(!a && typeof a === "object"); // true
null
是唯一一个“falsy”(也叫类 false;见第四章),但是在 typeof
检查中返回 "object"
的基本类型。
那么 typeof
可以返回的第七种字符串值是什么?
typeof function a(){ /* .. */ } === "function"; // true
很容易认为在 JS 中 function
是一种顶层的内建类型,特别是看到 typeof
操作符的这种行为时。然而,如果你阅读语言规范,你会看到它实际上是对象(object)的“子类型”。特别地,一个函数(function)被称为“可调用对象” —— 一个拥有 [[Call]]
内部属性、允许被调用的对象。
函数实际上是对象这一事实十分有用。最重要的是,它们可以拥有属性。例如:
function a(b,c) {
/* .. */
}
这个函数对象拥有一个 length
属性,它被设置为函数被声明时的形式参数的数量。
a.length; // 2
因为你使用了两个正式命名的参数(b
和 c
)声明了函数,所以“函数的长度”是 2
。
那么数组呢?它们是 JS 原生的,所以它们是一个特殊的类型咯?
typeof [1,2,3] === "object"; // true
不,它们仅仅是对象。考虑它们的最恰当的方法是,也将它们认为是对象的“子类型”(见第三章),带有被数字索引的附加性质(与仅仅使用字符串键的普通对象相反),并维护着一个自动更新的 .length
属性。