类型
JavaScript 定义了七种内建类型:1
2
3
4
5
6
7null
undefined
boolean
number
string
object
symbol —— ES6 中新增
typeof
使用typeof判断的出的七种类型1
2
3
4
5
6
7
8
9
10typeof 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
typeof null === "object"; // true
typeof function a(){ /* .. */ } === "function"; // true
单拍脑袋想的话,很容易理解 function(函数)会是 JS 中顶级的内建类型,尤其是它针对 typeof 运算符的表现。然而,如果你阅读相关的标准,会发现它实际上是对象类型(object)的子类型。更确切的说,函数是一种“可以被调用的对象”——一类拥有名为 [[Call]] 的内建属性且可以被调用的对象。
函数的length方法表示函数的参数个数
值和类型
在 JavaScript 中,变量不具有类型——值有类型。变量可以在任何时刻保存任何值。
换句话说,JS 并不是强类型的语言,编译引擎不会让一个变量始终保存和这个变量最开始所保存的值拥有相同的类型。变量可以保存一个 string 类型的值,并在接下来的赋值操作中保存一个number类型,以此类推。
如果你用 typeof 运算符去操作一个变量,看上去就像是在求“变量是什么类型?”,然而 JS 中的变量并不具有类型。所以,其实是在求“变量中保存的值是什么类型?”。
未定义和未声明
对于许多开发者都认为“未定义(undefined)”相当于是“未声明”的代名词,然而在 JS 中,这两个概念截然不同。
一个“未定义(undefined)”的变量是已经在当前作用域中声明了的,只不过是目前它并没有保存其他的值而已。而“未声明(undeclared)”则是指在当前作用域中没有声明的变量。
1 | var a; |
浏览器对于这一错误的描述可以说相当让人困惑。“b 尚未定义”很容易让人理解成“b 是未定义”。然后,“未定义”和“尚未定义”间的差别实在是太大了。如果浏览器要是能报个像“未找到变量 b”或是“b 尚未声明”之类的错误,就不会这么让人迷糊了。
同样的,typeof 运算符的特殊行为加重了这一困惑,请看例子:1
2
3var a;
typeof a; // "undefined"
typeof b; // "undefined"
对于“未声明”或着说“尚未定义”的变量,typeof 会返回 “undefined”。你会发现,虽然 b 是一个没有声明的变量,但是当我们执行 typeof b 的时候却没有报错。会出现这种情况,源于 typeof 运算符特殊的安全机制。
使用typeof对未声明的处理
1 | // 注意,这种方法会报错! |
提示:当你在对一个目前不存在的特性写“polyfill(腻子脚本)”的时候,你需要避免用 var 来声明变量 atob。如果你在 if 语句里面使用 var atob 来声明,即使 if 语句的条件不满足,变量的声明也会被提升到作用域的最顶级(详见本系列中的《作用域和闭包》)。在部分浏览器中,对一些特殊的全局的内建对象类型(常称为“宿主对象”,如浏览器中的 DOM 对象),这种重复的声明会报错。所以最好避免使用 var 来阻止变量提升。
总结
JavaScript 拥有七种内建类型:null,undefined,boolean,number,string,object,symbol。可以通过使用 typeof 运算符来对它们进行区分。其中null与object可以使用1
2var a = null;
(!a && typeof a === "object"); // true
这样符合判定
变量不具有类型,但值有。这些类型定义了值的行为。