计算机程序的唯一任务就是处理数据。从性质上来看,数据又分为很多种类型。比如描述你此刻的心情的一串文字,再比如描述地球到月球距离的一个数字。我们在这两种数据上所施加的操作是完全不同的。我们可能对前者“有感情的朗读”,却让后者“参与一个物理公式的计算”。所以我们说它们本质上是不同种类的数据,有必要区别对待。JavaScript语言把数据分成4中基本类型,它们是string(字符串)、number(数字)、boolean(布尔)和undefined(未定义)。请注意,它们的名称都是小写单词。接下来我们逐一讨论。
## (1)string
所谓字符,就是一个符号。可以是英文字母,例如大写字母H;可以是数字形式的符号,例如字符9;可以是各种标点符号,也可以是#、\*、@、!、{、$等等,中文、日文、俄文等等各种民族语言的符号也都算在内。为了表达某种特定含义,我们通常把许多这样的符号连成一长串,比如“banana”代表现实世界中的一种水果。在计算机中,我们把字符连成的长串叫做**字符串**。在上文中我们让警示框打印了一句“Hello world!”,这就是一个字符串。它由12个字符组成,其中包含10个英文字母、1个空格和1个感叹号。因此,我们说这个字符串的长度是12。JavaScript语言不会单独存储字符,它只处理字符串。字符串需要用双引号包围,哪怕是一个字符构成的字符串也应如此。我们把双引号称为字符串的**定界符**。如果你要输出中文,同样也需要使用双引号包围,例如"你好,世界!"。需要注意的是,在中文符号中也有全角的双引号,全角的双引号属于汉字。而英文中的半角双引号才能当做定界符,千万不要搞混淆。你可以试着运行下面的程序,弹出一个警示框:
```javascript
alert("JavaScript的世界不香吗?");
```
在这里,我隐去了暂不讨论的部分。不过你要时刻保证代码被放在\<script\>...\</script\>标签中的,并且第一行是严格模式的声明。其实,JavaScript也允许使用英文单引号作为字符串的定界符,这可能会使输出双引号或者单引号时稍微方便一些。看下面的例子:
```javascript
alert("JavaScript的世界不'香'吗?"); //JavaScript的世界不'香'吗?
alert('JavaScript的世界不"香"吗?'); //JavaScript的世界不"香"吗?
```
此外,还有一种特殊的字符串,就是我们常说的**空串**。空串不包含任何字符,也就是说它的长度为0。如果我们想让警示框输出一个空串,就写成下面的样子:
```javascript
alert(""); //两个双引号紧紧贴在一起
```
## (2)number
数字类型和数学中的差不多,不需要多讲,大家都很熟悉。例如5、4.2、-3.1、0等等,这些都是数字类型的常量。所谓**常量**,就是不会变化的量,是多少就写多少,是5就写5,是2就写2。我们可以写一些常量表达式,并用alert()函数输出它们的结果,例如:
```javascript
alert(5); //5
alert(5/2); //2.5,正斜杠(/)是除法操作符
```
我们还可以用标识符来代替数字。早在中学数学中,我们就曾经用字母代替数字进行计算,美其名曰“代数”,例如我们经常用英文字母$x$代替某个可能变化的物理量。在程序中,我们把这些代替具体值的标识符称作**变量**。在严格模式下,变量必须先声明再使用,其目的是为了避免由于程序员笔误而导致意外发生。看下面的例子:
```javascript
var n; //在严格模式下声明是必须的
n=5;
alert(n/2); //2.5
alert(m/2); //出错
```
在第1行中,我们用关键字var声明了标识符n,也就是明确地告知解释程序“在后面的程序中,n要作为变量来使用,请做好准备”。在第2行中,我们把常量5存放到n中。这叫做给变量n**赋值**。从此,n的值是5。第3行计算n除以2的商,并用警示框输出。第4行中,由于上文并没有声明标识符m,所以程序出错。在浏览器中按<kbd>F12</kbd>按钮,然后切换到Console(控制台)选项卡,可以在这里找到错误报告。在计算机的底层数据表示中,一个变量其实就是内存的一小块区域,给变量赋值的过程,实际上就是把数据写入到这块内存区域中。JavaScript允许在声明变量的同时给变量赋值,像下面那样:
```javascript
var n=5;
var m=n;
n=8;
alert(m/2); //2.5
```
上面代码第2行中,我们把n的值传给变量m。第3行n的值发生变化,但不会影响到m,两者代表内存中相互独立的区域。使用变量编程,可以让我们专心于运算法则,仅从形式上实现这一法则。而变量中具体的值是多少,则取决于程序运行时输入的数据。我们把这种用程序实现的运算法则叫做**算法**。我们现在可以写一个简单的算法小例子——通过给定的半径求圆面积。首先,我们来熟悉一下prompt()函数。alert()函数只是弹出警告,而prompt()函数不仅弹出提示,还要求用户输入信息。现在,我们用prompt()函数实现互动,要求用户输入圆的半径。用户输入完毕点击“确定”按钮,程序再用alert()输出圆的面积。
```javascript
var radius;
radius=prompt("请输入圆的半径:");
alert(3.14*radius*radius); //星号是乘法操作符
```
第2行,程序会弹出一个消息框并要求用户输入圆的半径。假设用户输入5,然后单击“确定”按钮,prompt()函数会将用户输入的5作为返回值,再通过赋值语句将这个返回值传送给变量radius。此时,radius中是数字5。第3行通过radius计算圆的面积并显示。
在JavaScript中,数字类型中还有两个很特殊的值,一个叫**Infinity**,意思是“无穷大”,另一个叫**NaN**,意思是“非数字(Not A Number)”。当你用5去除以0时,就会得到一个Infinity值:
```javascript
alert(5/0); //Infinity
```
说来倒也不稀奇,Infinity可以带正负。正无穷大就是Infinity,而负无穷大就是-Infinity。表达式-5/0的结果就是-Infinity。如果说Infinity值是一个数字类型,或许还比较容易令人接受。但是NaN值也是数字类型,似乎就有些匪夷所思。你可以直接输出这个常量,例如`alert(NaN);`,不过这么做没多大意义。常见的情况是在计算中得到一个无法描述的数字。比如想把4开算术平方根,得到的是数字2。但是,如果你把-4开平方,就会得到一个NaN值。再如,对一个完全没有数字形式的字符串强行进行了一次数学运算,也不会得到一个有意义的数字。看下面的例子:
```javascript
alert("China"/2); //NaN
```
世界上永远只有一个中国,任何企图将中国一分为二的想法都注定会失败。记住,虽然NaN值的含义是“非数字”,但它仍然是数字类型。
## (3)boolean
电灯有两种状态,要么亮,要么灭;人的性别有两种状态,要么男,要么女;门要么开,要么关;我们所处的时间要么是白天,要么是夜晚;一句话要么是事实,要么是谎言。现实世界里几乎所有事件都可以根据某种规则描述成相互对立的两种状态。为了在程序中描述这种对立的状态,我们定义了布尔类型的数据。布尔类型数据只有两个值,要么是true,要么是false。我们用前者描述肯定的、正确的、阳性的状态,用后者描述否定的、错误的、阴性的状态。我们可以单独输出一个布尔类型的常量:
```javascript
alert(true); //true
```
但大多数情况下,我们是通过对表达式进行计算从而得到一个布尔类型的结果。例如,3+7的和大于12吗?这个命题成立吗?换句话说,`3+7>12`这个算式成立吗?我们可以让程序来回答这个问题:
```javascript
alert(3+7>12); //false,说明这个判断不成立
```
布尔类型有自己的运算法则,相对于数字的**算术运算**而言,布尔类型的运算被称为**逻辑运算**。
* 逻辑非:将操作数映射为对立面(非真则假,非假则真);
| 表达式 | 结果 |
| :-----: | :---: |
| ! false | true |
| ! true | false |
- 逻辑与:两个操作数必须同时为真结果才为真,否则为假;
| 表达式 | 结果 |
| :------------: | :---: |
| false && false | false |
| false && true | false |
| true && false | false |
| true && true | true |
* 逻辑或:两个操作数中至少有一者为真结果为真,否则为假;
| 表达式 | 结果 |
| :--------------: | :---: |
| false \|\| false | false |
| false \|\| true | true |
| true \|\| false | true |
| true \|\| true | true |
JavaScript语言是一种脚本语言,JavaScript的逻辑运算其实是一种选择运算,我们在后文会详细介绍。
## (4)undefined
在JavaScript语言中,变量可以存储任何类型的数据,也可以在使用变量的过程中随时改变数据类型。我们可以用运算符typeof来查看一个变量(或常量)的数据类型。没错,typeof是运算符,所以把它放在变量(或常量)的前面即可,不需要加小括号。看下面的例子:
```javascript
var a;
a="5";
alert(typeof a); //string
a=5;
alert(typeof a); //number
a=true
alert(typeof a); //boolean
```
可是,一个变量在声明之后赋值之前,它里边是什么数据?又是什么类型呢?看下面的例子:
```javascript
var a; //声明了变量a,尚未对其赋值
alert(a); //undefined
alert(typeof a); //undefined
```
第2、3行的输出结果都是undefined(未定义)。第2行输出的是变量的值,第3行输出的是数据的类型名,两者拼写是一模一样的。也就是说,属于undefined类型的数据只有一个值,它就是undefined。我们完全可以给一个变量赋undefined值,就像可以给变量赋NaN值、Infinity值一样:
```javascript
var a=Infinity;
alert(typeof a); //number
a=NaN;
alert(typeof a); //number
a=undefined;
alert(typeof a); //undefined
```
这里需要特别说明一点,进行typeof运算之后得到的结果是一个字符串。比如`typeof 5`的运算结果事实上是字符串"number"。想想下面的例子输出的是什么:
```javascript
var a;
alert(typeof typeof a);
```