2.4 变量
在日常生活里,有些东西是固定不变的,有些东西则会发生变化。例如,人的姓名和生日是固定不变的,但心情和年龄却会随着时间的推移而发生变化。在谈论程序设计语言时,人们把那些会发生变化的东西称为变量(variable)。
我的心情会随着我的切身感受而变化。假设我有一个变量mood(意思是“心情”),我可以把此时此刻的心情存放到这个变量中。不管这个变量的值是“happy”还是“sad”,它的名字始终是mood。我可以随时改变这个值。
类似地,假设我现在的年龄是33岁。一年之后,我的年龄就是34岁。我可以使用变量age来存放我的年龄并在生日那天改变这个值。当我现在去查看age变量时,它的值是33;但一年之后,它的值将变成34。
把值存入变量的操作称为赋值(assignment)。我把变量mood赋值为“happy”,把变量age赋值为33。
下面是在JavaScript中对这些变量进行赋值的语法:
![]()
把值赋值给变量后,我们就可以说该变量包含这个值。例如,变量mood现在包含值“happy”,变量age现在包含值33。我们可以用如下所示的语句把这两个变量的值显示在一个弹出式警告窗口中:
![]()
下面是一个显示mood变量值的例子。

下面是一个显示age变量值的例子。

我们将在本书后面的章节中用变量做一些有用的事情,请大家耐心地阅读下去。
请注意,JavaScript允许程序员直接对变量进行赋值而无需提前对它们做出声明。这在许多程序设计语言中都是不允许的。有相当一部分程序设计语言要求在使用变量之前必须先对它做出“介绍”——术语称之为声明(declare)。
在JavaScript脚本中,如果程序员在对某个变量进行赋值之前未对其做出声明,赋值操作将自动声明该变量。虽然JavaScript没有要求程序员必须这么做,但提前对变量做出声明仍是一种良好的编程习惯。下面的语句对变量mood和age做出了声明:
![]()
每次只声明一个变量的做法并不是绝对的,JavaScript也允许程序员用一条语句声明多个变量,如下所示:
![]()
JavaScript甚至允许程序员把声明变量和对该变量进行赋值的这两项操作合起来一次完成:
![]()
我们甚至还可以像下面这样做:
![]()
像上面这样声明和赋值各有关变量是最有效率的做法,这条语句的效果相当于下面这些语句的总和:
![]()
在JavaScript语言里,变量和其他语法元素的名字都是区分字母大小写的。名字是mood的变量与名字是Mood、MOOD或mOOd的变量没有任何关系,它们不是同一个变量。下面的语句是在对两个不同的变量进行赋值:
![]()
JavaScript语法不允许变量的名字中包含空格或标点符号(但美元符号“$”例外)。下面这条语句将导致语法错误:
![]()
JavaScript变量名允许包含字母、数字、美元符号和下划线字符。为了让比较长的变量名有更好的可读性,可以在变量名中的适当位置插入一个下划线字符,就像下面这样:
![]()
在上面这条语句中,单词“happy”是JavaScript语言中的一个字面量(literal),也就是可以在JavaScript代码中直接写出来的数据内容。字面量除了它本身所给出的内容外无任何附加含义,用大力水手Popeye的话来说:“它就是它!”与此形成对照的是,单词“var”是JavaScript语言中的一个关键字,my_mood是一个变量的名字;它们都有自身内容以外的含义。
2.4.1 数据类型
变量mood的值是一个字符串类型的字面量,变量age的值则是一个数值类型的字面量。虽然它们是两种不同的数据类型,但在JavaScript脚本中为它们做出声明和进行赋值的语法无任何区别。有些程序设计语言要求程序员在声明变量的同时还必须明确地对其数据类型做出声明,这种做法称为类型声明(typing)。
要求程序员必须明确地对数据类型做出声明的程序设计语言被称为强类型(strongly typed)语言。像JavaScript这样不要求程序员进行类型声明的语言则被称为弱类型(weakly typed)语言。所谓弱类型意味着程序员可以随意改变某个变量的数据类型。
下面这条语句在强类型语言中是非法的,但在JavaScript语言里却完全没有问题:
![]()
JavaScript并不关心变量age的值是字符串还是数值。
接下来,我们一起看看JavaScript语言中最重要的几种数据类型。
1. 字符串
字符串由零个或多个字符构成。字符包括字母、数字、标点符号和空格。字符串必须放在引号里——单引号或双引号都允许使用。下面这两条语句有着同样的效果:
![]()
你们可以随意选用,但最好能根据字符串所包含的字符来加以选择:如果字符串包含双引号字符,就应该把整个字符串放在单引号中;如果字符串包含单引号字符,就应该把整个字符串放在双引号中:
![]()
如果想在上面这条语句中使用单引号,就必须保证字母“n”和“t”之间的单引号能被解释为这个字符串的一部分。换句话说,必须保证这个单引号被解释为这个字符串里的一个字符,而不是被解释为这个字符串的结束标志。这个问题需要使用字符转义(escaping)功能来解决。在JavaScript语言中,对字符进行转义需要用到反斜杠字符,如下所示:
![]()
类似地,如果想用双引号来给出一个本身就包含着双引号字符的字符串,就必须用反斜杠字符对这个字符串中的双引号进行转义,如下所示:
![]()
为了对其他字符进行转义而添加到字符串中的那些反斜杠字符并不是字符串的实际组成部分。你们可以自己去验证这一点:把下面这段代码添加到example.js文件中,然后重新加载test.html文件:
![]()
下面是用反斜杠字符对有关字符进行转义后的一个屏幕输出示例。

就个人而言,笔者比较喜欢用双引号来给出字符串。作为一种良好的编程习惯,不管你们选择的是双引号还是单引号,最好能在整个脚本中保持一致。如果在同一个脚本中一会儿使用双引号,一会儿又使用单引号,代码很快就会变得难以阅读和理解。
2.数值
如果想让某个变量包含一个数值,不用限定它必须是一个整数。JavaScript允许程序员使用带小数点的数值,并且允许数值是任意位数,这类数值称为浮点数(floating-point number):
![]()
还可以使用负数。负数的表示方式是在有关数值的前面加上一个减号(-),如下所示:
![]()
JavaScript并不要求负数必须是一个整数:
![]()
以上这些都是数值数据类型的例子。
3.布尔值
另一种重要的JavaScript数据类型是布尔(boolean)类型。
布尔数据只有两种可取值——true或false。假设需要这样一个变量:如果我正在睡觉,这个变量将存储一个值;如果我没有睡觉,这个变量将存储另一个值。可以用字符串数据类型来解决这个问题——只要根据具体情况把有关变量赋值为“sleeping”或“not sleeping”即可达到目的,但布尔数据类型显然是一个更好的选择:
![]()
从某种意义上讲,为计算机设计程序就是与布尔值打交道。作为最基本的事实,所有的电子电路只能识别和使用布尔数据:电路中有电流或是没有电流。根据具体情况,这两种状态可以代表“真或假”、“是或否”或者“1或0”,但不管它们代表什么,这两种状态绝不可能同时出现——换句话说,在任意时刻只能使用两种可取值中的一种。
与字符串值不同,千万不要把布尔值用引号括起来。布尔值false与字符串值'false'或"false"是两回事!
下面这条语句将把变量married设置为布尔值true:
![]()
下面这条语句将把变量married设置为一个包含着单词”true”的字符串:
![]()
2.4.2 数组
字符串、数值和布尔值都属于离散值(scalar)。如果某个变量是离散的,它在任意时刻就只能有一个值。如果想用一个变量来存储一组值,就需要使用数组(array)。
数组是由名字相同的多个值构成的一个集合,集合中的每个值都是这个数组的元素(element)。例如,我们可以用名为beatles的变量来保存Beatles乐队全体四位成员的姓名。
在JavaScriptd脚本中,数组要用关键字Array来声明。在声明数组的同时,程序员还可以对这个数组的元素个数,也就是这个数组的长度(length),做出规定:
![]()
有时,我们无法提前预知某个数组最终会容纳多少个元素。这没有关系,JavaScript并不要求在声明数组时必须给出它的元素个数,我们完全可以在声明数组时不给出明确具体的元素个数:
![]()
向数组中添加元素的操作称为填充(populating)。在填充数组时,不仅需要给出新元素的值,还需要在数组中为新元素指定存放位置,这个位置要通过下标(index)给出。数组里的每个元素都有一个相应的下标。在语句中,下标值必须放在方括号内,如下所示:
![]()
现在来填充刚才声明的beatles数组。我们将按照人们在提到Beatles乐队成员时的传统顺序(即John、Paul、George和Ringo)进行。首先是第一个下标和元素:
![]()
以0而不是1作为第一个下标值多少会让人感到有些不习惯,但JavaScript语言就是这么规定的,所以我们这里只能这么做。这一点很重要,但也很容易被忘记,初出茅庐的程序员在刚接触JavaScript数组时经常在这个问题上犯错误。
下面是声明和填充beatles数组的全过程:

有了上面这些代码,我们即可在脚本中通过下标值“2”(beatles[2])来检索取值为“George”的元素了。请注意,beatles数组的长度是4,但它最后一个元素的下标却是3。因为数组下标是从0开始计数的,你们或许需要一些时间才能习惯这一事实。
像上面这样填充数组未免有些麻烦。这里有一种相对简单的方式:在声明数组的同时对它进行填充。这么做时别忘了用逗号把各个元素分隔开:
![]()
上面这条语句会为beatles数组中的每个元素自动分配一个下标:第一个下标是0,第二个是1,依此类推。因此,beatles[2]仍将对应于取值为“George”的元素。
我们甚至用不着明确地表明我们是在创建数组。事实上,只需用一对方括号把各个元素的初始值括起来就足以创建出我们想要的数组了:
![]()
不过,在声明或填充数组时写出Array关键字是一个良好的编程习惯,这可以提高JavaScript脚本的可读性,并让我们一眼就看出哪些变量是数组。
数组元素不必非得是字符串。可以把一些布尔值存入一个数组,还可以把一组数值存入一个数组:
![]()
甚至可以把这三种数据类型混在一起存入一个数组:
![]()
数组元素还可以是变量:
![]()
这将把beatles数组的第一个元素赋值为“John”。
数组元素的值还可以是另一个数组的元素。下面两条语句将把beatles数组的第二个元素赋值为“Paul”:
![]()
事实上,数组还可以包含其他的数组!数组中的任何一个元素都可以把一个数组作为它的值:
![]()
现在,beatles数组的第一个元素的值是另外一个数组。要想获得那个数组里的某个元素的值,我们需要使用更多的方括号。beatles[0][0]的值是“John”,beatles[0][1]的值是1940,beatles[0][2]的值是false。
这是一种功能相当强大的存储和获取信息的方式,但如果我们不得不记住每个下标数字的话,编程工作将是一种非常痛苦和麻烦的体验。还好,有一种办法可以让我们以更可读的方式去填充数组。
关联数组
beatles数组是数值数组的一个典型例子:每个元素的下标是一个数字,每增加一个元素,这个数字就依次增加1。第一个元素的下标是0,第二个元素的下标是1,依此类推。
如果在填充数组时只给出了元素的值,这个数组就将是一个数值数组,它的各个元素的下标将被自动创建和刷新。
我们可以通过在填充数组时为每个新元素明确地给出下标的方式来改变这种默认的行为。在为新元素给出下标时,不必局限于整数数字。数组下标可以是字符串:

这称为关联数组(associative array)。从某种意义上讲,完全可以把所有的数组都看作是关联数组。尽管数值数组的下标是由系统自动创建的一些数字,但每个下标仍关联着一个特定的值。因此,数值数组完全可以被当作关联数组的一种特例来对待。
用关联数组来代替数值数组的做法意味着,我们可以通过各元素的名字而不是一个下标数字来引用它们。这可以大大提高脚本的可读性。
下面,我们将创建一个新的beatles数组,并用刚才创建的lennon数组来填充它的第一个元素。别忘了,数组的元素可以是另一个数组:
![]()
现在,可以通过一些有意义的名字去访问所需要的某个元素了。beatles[0]["name"]的值是“John”,beatles[0]["year"]的值是1940,beatles[0]["living"]的值是false。
在此基础上,还可以做进一步的改进:把beatles数组也填充为关联数组而不是数值数组。这样一来,我们就可以用“drummer”或“bassist”等更有意义且更容易记忆的字符串值,而不是一些枯燥乏味的整数作为下标去访问这个数组里的元素了:
![]()
现在,beatles["vocalist"]["name"]的值是“John”,beatles["vocalist"]["year"]的值是1940,beatles["vocalist"]["living"]的值是false。







