|
2.3 ECMAScript类型 |
本节介绍关于ECMAScript类型的知识,这是ECMAScript语法基础中非常重要的部分。
根据Ecma-262规范中的定义,变量可以为两种类型的值,即原始值和引用值。那么这两种类型的值有什么区别呢?我们先看一下官方给出的原始值和引用值的定义。
另外,这里提到关于指针的概念,对于学习过C语言的读者会比较容易理解引用值的概念。如果读者对指针的概念比较模糊,建议最好选一本C语言教材认真阅读一下,相信一定有很大的帮助。
根据Ecma-262规范,在为变量赋值时,ECMAScript解释程序必须判断该值是原始类型还是引用类型。ECMAScript解释程序在处理原始类型和引用类型的变量赋值机制上,采用了不同的方式。
ECMAScript的原始类型包括Undefined、Null、Boolean、Number和String五大类型。因此,ECMAScript解释程序在为变量赋值时,就会先判断该值是否为这五大原始类型。而Ecma-262规范对于引用类型的定义比较抽象,其实引用类型就是一个对象,类似于Java语言中类(class)的概念。如果ECMAScript解释程序判断出值不是原始类型,那么就是引用类型。
由于原始类型的值所占据的空间是固定的,因此可将其存储在占用较小内存区域的“栈”中,这种存储机制便于ECMAScript解释程序迅速查找变量的值。而如果一个值是引用类型,那么其存储空间将从“堆”中分配。
“栈”与“堆”是计算机操作系统中两个十分重要的概念,这是因为二者作用的重要性。从数据结构上理解,“栈”是一种“先进后出、后进先出”的存储结构;“堆”是一种树形存储结构。从计算机操作系统原理上理解,“栈”一般位于一级缓存中;而“堆”一般位于二级缓存中,一级缓存的存取速度自然是快于二级缓存的。
“栈”与“堆”的结构关系到变量的存储机制。由于ECMAScript引用值的大小会改变,因此不能将其存储在“栈”中,否则会降低变量查找访问的速度。而指向引用值的指针(pointer)是存储在“栈”中的,该值是该引用值对象存储在堆中的地址,因为地址的大小是固定的,所以将其存储在栈中是没有任何问题的。
在许多编程语言中,字符串都是被当作引用类型处理的,而不是原始类型。这是因为字符串的长度大小是可变的,不适于作为原始类型来处理。不过,ECMAScript语法改变了这一点,字符串在ECMAScript中是作为原始类型来处理的。自然,ECMAScript字符串的处理速度会更快。
ECMAScript语法定义五种原始类型(primitive type),即前文中提到的Undefined、Null、Boolean、Number和String。根据ECMA-262规范中的描述,将术语“类型(type)”定义为“值的一个集合”,其中每种原始类型均定义了其所包含值的范围及其字面量的表示形式。
ECMAScript语法提供“typeof”运算符来判断一个值是否在某种类型的范围内。设计人员不但可以用该运算符判断一个值是否表示一种原始类型,还可以判断出其具体表示哪种原始类型。在JS脚本中使用“typeof”运算符将返回下列值之一:
下面的几个小节,将为读者逐一讲解ECMAScript语法定义的这五种原始类型及其应用实例。
首先介绍ECMAScript语法中的第一种原始类型——Undefined。对于Undefined类型其实只有一个值,即“undefined”。当声明的变量未进行初始化时,该变量的默认值就是undefined。
ECMAScript语法中的Undefined类型学习起来是一个难点,通过文字描述来概括总结多少还是有点晦涩难懂,下面还是通过具体实例帮助读者学习理解Undefined原始类型的概念与用法。
先看第一个关于Undefined类型的代码示例(详见源代码ch02目录中ch02-js-undefineda.html文件)。
【代码2-5】
01 <script type="text/javascript"> 02 console.log("print undefined is : " + undefined); 03 console.log("print typeof undefined is : " + typeof undefined); 04 </script>
关于【代码2-5】的分析如下:
第02行代码直接在浏览器控制台窗口中输出了“undefined”,目的是看一下Undefined类型在页面中的输出结果;
第03行代码直接在浏览器控制台窗口中输出了“typeof undefined”,目的是看一下通过“typeof”运算符操作后的Undefined类型在页面中的输出效果。
页面效果如图2.5所示。Undefined类型和通过“typeof”运算符操作后的Undefined类型,在控制台中的输出结果均是“undefined”。
图2.5 Undefined原始类型(1)
下面,继续看第二个关于Undefined类型的代码示例(详见源代码ch02目录中ch02-js-undefined-b.html文件)。
【代码2-6】
01 <script type="text/javascript"> 02 var v_undefined; 03 console.log(v_undefined); 04 console.log(typeof v_undefined); 05 </script>
页面效果如图2.6所示。如果变量定义后未初始化,则无论是直接输出该变量,或是通过“typeof”运算符操作后,在控制台中的输出结果均是“undefined”。
图2.6 Undefined原始类型(2)
下面,继续看第三个关于Undefined类型的代码示例(详见源代码ch02目录中ch02-js-undefined-c.html文件)。
【代码2-7】
01 <script type="text/javascript"> 02 console.log(typeof v_undefined); 03 console.log(v_undefined); 04 </script>
页面效果如图2.7所示。如果变量未声明,则通过“typeof”运算符操作后的变量在控制台中的输出结果仍是“undefined”。但如果未经过“typeof”运算符操作,直接在控制台中输出该未声明的变量(也未初始化),就会提示JS脚本错误,如图2.7中箭头所示。
图2.7 Undefined原始类型(3)
下面,继续看第四个关于Undefined类型的代码示例(详见源代码ch02目录中ch02-js-undefined-d.html文件)。
【代码2-8】
01 <script type="text/javascript"> 02 var v_undefined; 03 if(v_undefined == undefined) { 04 console.log("if v_undefined == undefined is true."); 05 } else { 06 console.log("if v_undefined == undefined is false."); 07 } 08 </script>
声明后未初始化定义的变量,在逻辑判断上与Undefined原始类型是相等的,如图2.8中箭头所指的结果所示。
图2.8 Undefined原始类型(4)
最后,看一下第五段关于Undefined类型的代码示例(详见源代码ch02目录中ch02-js-undefined-e.html文件)。
【代码2-9】
01 <script type="text/javascript"> 02 var v_func_undefined = (function(){})(); 03 console.log(v_func_undefined); 04 </script>
页面效果如图2.9所示。当函数未定义明确的返回值时,函数表达式变量(v_func_undefined)获取的返回值也是“undefined”,如图2.9中箭头所指的结果所示。
以上就是关于Undefined类型的一组代码示例,希望通过这组代码示例能够帮助读者进一步加深对ECMAScript原始类型“Undefined”的理解。
图2.9 Undefined原始类型(5)
在这一小节中,我们继续介绍ECMAScript语法中的第二种原始类型——Null。Null与Undefined类似,也是只有一个值的原始类型,其只有一个专用值,即“null”。严格意义上讲,值“undefined”实际上是从值“null”派生而来的。正因为如此,ECMAScript语法将“undefined”和“null”定义为相等的。
ECMAScript语法中的Null类型学习起来也是一个难点,仅仅通过文字描述估计还是无法让读者掌握其真正的使用方法,下面还是通过具体实例来帮助读者学习理解Null原始类型的概念与用法。
先看第一个关于Null类型的代码示例(详见源代码ch02目录中ch02-js-null-a.html文件)。
【代码2-10】
01 <script type="text/javascript"> 02 console.log("print null is : " + null); 03 console.log("print typeof null is : " + typeof null); 04 </script>
关于【代码2-10】的分析如下:
第02行代码直接在浏览器控制台窗口中输出了“null”,目的是看一下Null类型在页面中的输出结果;
第03行代码直接在浏览器控制台窗口中输出了“typeof null”,目的是看一下通过“typeof”运算符操作后的Null类型在页面中的输出结果。
页面效果如图2.10所示。浏览器控制台中直接输出Null类型的结果是“null”,而通过“typeof”运算符操作后的Null类型在浏览器控制台中输出的结果却是“object”。
图2.10 Null原始类型(1)
读者也许会有疑问了,为什么通过“typeof”运算符操作后的“null”值会返回“object”的结果呢?其实这源于JavaScript脚本语言的最初实现版本中的一个错误,然后又恰恰被ECMAScript语法沿用了。现在,“null”值被认为是对象的占位符,这样似乎能够解释这一矛盾。但是,从严格意义的技术上来讲,“null”仍然是原始值,Null也仍然是ECMAScript原始类型。
下面,继续看第二个关于Null类型的代码示例(详见源代码ch02目录中ch02-js-null-b.html文件)。
【代码2-11】
01 <script type="text/javascript"> 02 var v_null = null; 03 console.log(v_null); 04 console.log(typeof v_null); 05 </script>
页面效果如图2.11所示。浏览器控制台中直接输出了变量(v_null)类型的结果是“null”,而通过“typeof”运算符操作后的变量(v_null)在浏览器控制台中输出的结果是预想中的“object”。
图2.11 Null原始类型(2)
下面,继续看一个关于Null类型与Undefined类型比较有趣的的代码示例(详见源代码ch02目录中ch02-js-null-c.html文件)。
【代码2-12】
01 <script type="text/javascript"> 02 if(null == undefined) { 03 console.log("if null == undefined is true."); 04 } else { 05 console.log("if null == undefined is false."); 06 } 07 </script>
页面效果如图2.12所示。值(null)与值(undefined)在逻辑等于判断上是相等的,如图2.12中箭头所指的结果所示。
图2.12 Null原始类型与Undefined原始类型比较
不过,尽管值(null)与值(undefined)在逻辑等于判断上是相等的,但是这两个值的具体含义还是有所区别的。为变量赋“null”值表示该对象目前并不存在,也可以理解为仅仅是一个空的占位符(如前文所述)。而将变量定义为“undefined”值则是声明了变量但未对其进行初始化赋值(如前文代码示例)。
另外,当为函数方法定义返回的是对象类型时,如果找不到该对象,则返回值通常就是“null”。而当尝试获取函数方法的返回值时,如果该函数方法未定义返回值,则返回值通常就是“undefined”。
本小节继续介绍ECMAScript语法中的第三种原始类型——Boolean。Boolean原始类型是ECMAScript语法中定义的非常常用的类型之一。Boolean类型有两个值,即大家所熟悉的“true”和“false”。
下面来看一个关于Boolean类型的代码示例(详见源代码ch02目录中ch02-js-boolean.html文件)。
【代码2-13】
01 <script type="text/javascript"> 02 var v_b_true = true; 03 console.log(v_b_true); 04 console.log(typeof v_b_true); 05 if(v_b_true) { 06 console.log("v_b_true is true."); 07 } else { 08 console.log("v_b_true is false."); 09 } 10 if(v_b_true == 1) { 11 console.log("v_b_true == 1."); 12 } else { 13 console.log("v_b_true != 1."); 14 } 15 var v_b_false = false; 16 console.log(v_b_false); 17 console.log(typeof v_b_false); 18 if(v_b_false) { 19 console.log("v_b_false is true."); 20 } else { 21 console.log("v_b_false is false."); 22 } 23 if(v_b_false == 0) { 24 console.log("v_b_false == 0."); 25 } else { 26 console.log("v_b_false != 0."); 27 } 28 </script>
关于【代码2-13】的分析如下:
第02行代码定义了一个变量(v_b_true),并初始化赋值为“true”;
第03行代码直接在浏览器控制台窗口中输出了变量(v_b_true),目的是看一下Boolean类型在页面中的输出效果;
第04行代码直接在浏览器控制台窗口中输出了“typeof v_b_true”,目的是看一下通过“typeof”运算符操作后的Boolean类型在页面中的输出效果;
第05~09行代码直接通过“if”条件运算符判断变量(v_b_true)的逻辑值,并根据逻辑运算结果在浏览器控制台窗口中进行相应的输出;
第10~14行代码直接通过“if”条件运算符判断变量(v_b_true)与数值“1”是否逻辑相等,并根据逻辑运算结果在浏览器控制台窗口中进行相应的输出。这样测试的目的是源于C语言和Java语言的语法中,布尔值“真”与数值“1”是逻辑相等的,因此查看一下在ECMAScript语法中是否也是如此;
第15~27行代码与第02~14行代码的功能类似,只不过第15行代码定义的变量(v_b_false),其初始化赋值为“false”,目的就是测试一下布尔值“false”的输出结果。
页面效果如图2.13所示。浏览器控制台中直接输出变量(v_b_true)的结果是“true”,而通过“typeof”运算符操作后的变量(v_b_true)在浏览器控制台中输出的结果就是“Boolean”类型;而通过“if”条件运算符判断变量(v_b_true)与数值“1”是否逻辑相等的结果表明,Boolean值“true”在逻辑上是等于数值“1”的;同样,Boolean值“false”与数值“0”在逻辑也是相等的。
图2.13 Boolean原始类型
通过以上的测试结果的学习,相信读者对于ECMAScript语法中的Boolean类型的使用会有一个比较清楚的理解。
本小节继续介绍ECMAScript语法中的第四种原始类型——Number。Number原始类型是ECMAScript语法中定义的比较特殊的类型之一。特殊之处就在于Number类型既可以表示32位整数值,也可以表示64位浮点数值。对于直接定义的任意类型数值,ECMAScript语法均识别为Number类型的值,故而Number类型使用起来也是非常灵活的。
下面,先看第一个关于Number类型十进制数值的代码示例(详见源代码ch02目录中ch02-js-number-dec.html文件)。
【代码2-14】
01 <script type="text/javascript"> 02 var i = 123; 03 var j = 456; 04 var sum = i + j; 05 console.log("sum = " + sum); 06 console.log(i.toString() + j.toString()); 07 </script>
关于【代码2-14】的分析如下:
第04行代码定义了变量(sum),并初始化赋值为变量(i)和变量(j)相加的和;
第06行代码分别通过Number对象的toString()方法将变量(i)和变量(j)转换为字符串类型,并通过运算符“+”执行字符串连接操作,然后将操作后的结果在浏览器控制台窗口中进行了输出。
页面效果如图2.14所示。可以看出Number类型十进制数值可以通过toString()方法转换为字符串类型。
图2.14 Number原始类型(1)
下面,继续看第二个关于Number类型八进制数值的代码示例(详见源代码ch02目录中ch02-js-number-oct.html文件)。
【代码2-15】
01 <script type="text/javascript"> 02 var v_dec = 147; 03 console.log("147 = " + v_dec); 04 var v_oct = 0147; // TODO: 定义八进制数值 05 console.log("0147 = " + v_oct); 06 var v_oct_oct = v_oct + v_oct; 07 console.log("0147 + 0147 = " + v_oct_oct); 08 var v_dec_oct = v_dec + v_oct; 09 console.log("147 + 0147 = " + v_dec_oct); 10 </script>
页面效果如图2.15所示。第05行代码在浏览器控制台窗口中输出变量(v_oct)的内容为“103”,而不是初始化定义的数值“0147”,这说明ECMAScript语法对八进制变量返回的是换算后的十进制数值;同样,第07行代码在浏览器控制台窗口中输出的变量(v_oct_oct)的内容为“206”,也是十进制相加运算得出的结果。
另外,第09行代码在浏览器控制台窗口中输出的变量(v_dec_oct)的内容为250,是十进制数值147和十进制数值103相加运算得出的结果。这就表明在ECMAScript语法中,八进制与十进制运算时,默认都是换算成十进制来计算的。八进制数值如此,十六进制数值也是一样的。
图2.15 Number原始类型(2)
下面,继续看第三个关于Number类型十六进制数值的代码示例(详见源代码ch02目录中ch02-js-number-hex.html文件)。
【代码2-16】
01 <script type="text/javascript"> 02 var v_dec = 1234; 03 console.log("1234 = " + v_dec); 04 var v_oct = 0147; // TODO: 定义八进制数值 05 console.log("0147 = " + v_oct); 06 var v_hex = 0x12ff; // TODO: 定义十六进制数值 07 console.log("0x12ff = " + v_hex); 08 var v_hex_hex = v_hex + v_hex; 09 console.log("0x12ff + 0x12ff = " + v_hex_hex); 10 var v_dec_hex = v_dec + v_hex; 11 console.log("1234 + 0x12ff = " + v_dec_hex); 12 var v_oct_hex = v_oct + v_hex; 13 console.log("0147 + 0x12ff = " + v_oct_hex); 14 </script>
页面效果如图2.16所示。第07行代码在浏览器控制台窗口中输出的变量(v_hex)的内容为4863,而不是初始化定义的数值“0x12ff”,这说明ECMAScript语法对十六进制变量同样返回的是换算后的十进制数值。第09行代码在浏览器控制台窗口中输出的变量(v_hex_hex)的内容为9726,也是十进制运算相加得出的结果。
另外,第11行代码在浏览器控制台窗口中输出的变量(v_dec_hex)的内容为6097,是十进制数值1234和十进制数值4863相加运算得出的结果。这就表明在ECMAScript语法中,十进制与十六进制运算时,默认都是换算成十进制来计算的。同样,第13行代码在浏览器控制台窗口中输出的变量(v_oct_hex)的内容为4966,是十进制数值103和十进制数值4863相加运算得出的结果。这同样表明在ECMAScript语法中,八进制与十六进制运算时,也默认都是换算成十进制来计算的。
图2.16 Number原始类型(3)
下面,继续看第四个关于Number类型浮点数值的代码示例(详见源代码ch02目录中ch02-js-number-float.html文件)。
【代码2-17】
01 <script type="text/javascript"> 02 // TODO: 定义浮点数值必须使用小数点和至少一位小数 03 var v_f = 16.8; 04 console.log("16.8 = " + v_f); 05 var v_f_f = v_f + v_f; 06 console.log("16.8 + 16.8 = " + v_f_f); 07 var v_i = 168; 08 var v_i_f = v_i + v_f; 09 console.log("168 + 16.8 = " + v_i_f); 10 var v_str = "16.8"; 11 var v_f_str = v_f + v_str; 12 console.log("16.8 + '16.8' = " + v_f_str); 13 </script>
页面效果如图2.17所示。第06行代码在浏览器控制台窗口中输出的变量(v_f_f)的内容为33.6,正是两个浮点数16.8相加后的结果;第09行代码在浏览器控制台窗口中输出的变量(v_i_f)的内容为184.8,正是整数168和浮点数16.8相加后的结果,且整数与浮点数运算后自动保存为浮点数类型。
另外,第12行代码在浏览器控制台窗口中输出的内容为“16.816.8”,这明显是一个字符串类型。这就明显表明在ECMAScript语法中,浮点数与字符串通过运算符“+”连接时,浮点数会被当成字符串来处理,而此时的运算符“+”不再是加法运算,而是字符串连接运算。
图2.17 Number原始类型(浮点数)
其实,读者可以测试一下整数类型与字符串类型通过运算符“+”连接后的结果,同样是字符串连接运算。由此可以推断出,无论是整数或是浮点数,在运算之前均是被存储成字符串类型的,而ECMAScript语法中确实也是这样规定的。这就与传统的C语言不同,【代码2-17】中第11行代码的表达式在C语言中,编译时一定会报错。这也恰恰说明JavaScript语言的弱类型性。
最后,对于Number类型中的非常大或非常小的数值,一般采用科学记数法来表示浮点数。具体说就是把一个很大或很小的数值表示为数字(包括十进制数字)加e(或E),后面加乘以10的幂。
接下来,继续看第五个关于Number类型科学记数法的代码示例(详见源代码ch02目录中ch02-js-number-e.html文件)。
【代码2-18】
01 <script type="text/javascript"> 02 // TODO: 科学记数法使用 e加上10的幂来表示 03 var v_e_plus = 1.68e8; // TODO: 很大的数的表示方法 04 console.log("1.68e8 = " + v_e_plus); 05 var v_e_neg_6 = 0.000000168; // TODO: 很小的数的表示方法 06 console.log("0.000000168 = " + v_e_neg_6); 07 var v_e_neg_5 = 0.00000168; // TODO: 很小的数的表示方法 08 console.log("0.000000168 = " + v_e_neg_5); 09 </script>
变量(v_e_neg_6)与变量(v_e_neg_5)的区别就是小数点后的前导0的个数不同,变量(v_e_neg_6)是六个0,而变量(v_e_neg_5)是五个0。
页面效果如图2.18所示。第04行代码在浏览器控制台窗口中输出的变量(v_e_plus)的内容为168000000,正是科学记数法1.68e8(1.68×10 8 )通过运算后的结果。
第06行代码在浏览器控制台窗口中输出的变量(v_e_neg_6)的内容为1.68e-7,正是浮点数0.000000168转换为科学记数法后的结果。而第08行代码在浏览器控制台窗口中输出的变量(v_e_neg_5)的内容,并没有转换为科学记数法。这是因为ECMAScript语法规定,默认会把具有6个或6个以上前导0的浮点数自动转换成科学记数法。
图2.18 Number原始类型(科学记数法)
ECMAScript语法中为Number原始类型定义了几个特殊值。下面,我们就逐一介绍这些Number类型特殊值。
首先,就是Number.MAX_VALUE和Number.MIN_VALUE这两个特殊值,其分别定义了Number值集合的上下界限。ECMAScript语法规定所有数值都必须介于这两个值之间。不过,如果是通过计算生成的数值则可以不在这两个值之间。
下面来看一个关于特殊值Number.MAX_VALUE和Number.MIN_VALUE的代码示例(详见源代码ch02目录中ch02-js-number-min-max.html文件)。
【代码2-19】
01 <script type="text/javascript"> 02 // TODO: Number 特殊值 03 console.log("Number类型上界限:"+Number.MAX_VALUE); // TODO: Number上限值 04 console.log("Number类型下界限:"+Number.MIN_VALUE); // TODO: Number下限值 05 </script>
关于【代码2-19】的分析如下:
这段代码直接在浏览器控制台窗口中输出了Number.MAX_VALUE和Number.MIN_VALUE这两个特殊值的内容。页面效果如图2.19所示。
图2.19 Number类型特殊值(上下界限)
当通过计算生成的数值大于Number.MAX_VALUE时,其会被赋予特殊值Number.POSITIVE_INFINITY,该值表示正无限大的数值,也就是不再有具体的数值。同样的,当通过计算生成的数值小于Number.MIN_VALUE时,其会被赋予特殊值Number.NEGATIVE_INFINITY,该值表示负无限大的数值,同样也是不再有具体的数值。当通过计算返回的是无穷大值时,该值也就不能再用于其他计算。
ECMAScript语法中有专用值表示正无穷大(Infinity)和负无穷大(-Infinity)。事实上,Number.POSITIVE_INFINITY的值就是Infinity,而Number.NEGATIVE_INFINITY的值就是-Infinity。
下面来看一个关于特殊值Number.POSITIVE_INFINITY和Number.NEGATIVE_INFINITY的代码示例(详见源代码ch02目录中ch02-js-number-posi-nega-infinity.html文件)。
【代码2-20】
01 <script type="text/javascript"> 02 // TODO: Number 特殊值 03 console.log("Number.POSITIVE_INFINITY(正无穷大) : " + Number.POSITIVE_INFINITY); 04 console.log("Number.NEGATIVE_INFINITY(负无穷大) : " + Number.NEGATIVE_INFINITY); 05 </script>
关于【代码2-20】的分析如下:
这段代码直接在浏览器控制台窗口中输出了Number.POSITIVE_INFINITY和Number.NEGATIVE_INFINITY这两个特殊值的内容。
页面效果如图2.20所示。浏览器控制台中输出了特殊值Number.POSITIVE_INFINITY和Number.NEGATIVE_INFINITY的具体值,分别就是特殊值正无穷大(Infinity)和负无穷大(-Infinity)。
既然无穷大数可以是正数也可以是负数,所以可用一个方法判断一个数是否是有穷的。ECMAScript语法中提供了一个isFinite()函数方法,其可以判断数值是否为非无穷大。
图2.20 Number类型特殊值(无穷大)
下面来看一个通过isFinite()函数方法判断数值是否为无穷大的代码示例(详见源代码ch02目录中ch02-js-number-isInfinity.html文件)。
【代码2-21】
01 <script type="text/javascript"> 02 // TODO: Number 特殊值 03 if(isFinite(1)) { 04 console.log("isFinite(1) is not Infinity."); 05 } else { 06 console.log("isFinite(1) is Infinity."); 07 } 08 if(isFinite(Number.MAX_VALUE)) { 09 console.log("isFinite(Number.MAX_VALUE) is not Infinity."); 10 } else { 11 console.log("isFinite(Number.MAX_VALUE) is Infinity."); 12 } 13 if(isFinite(Number.MAX_VALUE * 2)) { 14 console.log("Number.MAX_VALUE * 2 = " + Number.MAX_VALUE * 2); 15 console.log("isFinite(Number.MAX_VALUE * 2) is not Infinity."); 16 } else { 17 console.log("Number.MAX_VALUE * 2 = " + Number.MAX_VALUE * 2); 18 console.log("isFinite(Number.MAX_VALUE * 2) is Infinity."); 19 } 20 if(isFinite(Number.POSITIVE_INFINITY)) { 21 console.log("isFinite(Number.POSITIVE_INFINITY) is not Infinity."); 22 } else { 23 console.log("isFinite(Number.POSITIVE_INFINITY) is Infinity."); 24 } 25 </script>
页面效果如图2.21所示。数值1为非无穷大;特殊值Number.MAX_VALUE同样也为非无穷大;而两倍的特殊值Number.MAX_VALUE和特殊值Number.POSITIVE_INFINITY则为无穷大。
图2.21 Number类型特殊值(判断是否为非无穷大)
最后要介绍的Number类型特殊值是NaN,其表示非数值(Not a Number)。在ECMAScript语法中,NaN是一个非常奇怪的特殊值,奇怪之处就是其与自身逻辑判断上是不相等的。NaN与Infinity一样都是不能用于算术计算的。另外,ECMAScript语法中提供了一个isNaN()函数方法,其可以判断某个数据类型是否为非数值。
下面来看一个关于特殊值NaN和isNaN()函数方法的代码示例(详见源代码ch02目录中ch02-js-isNaN.html文件)。
【代码2-22】
01 <script type="text/javascript"> 02 console.log("NaN is " + NaN); 03 console.log("typeof NaN is " + typeof NaN); 04 if(isNaN(NaN)) { 05 console.log("isNaN(NaN) return true."); 06 } else { 07 console.log("isNaN(NaN) return false."); 08 } 09 if(isNaN(123)) { 10 console.log("isNaN(123) return true."); 11 } else { 12 console.log("isNaN(123) return false."); 13 } 14 if(isNaN("123")) { 15 console.log("isNaN('123') return true."); 16 } else { 17 console.log("isNaN('123') return false."); 18 } 19 if(isNaN("abc")) { 20 console.log("isNaN('abc') return true."); 21 } else { 22 console.log("isNaN('abc') return false."); 23 } 24 if(NaN == NaN) { 25 console.log("NaN == NaN return true."); 26 } else { 27 console.log("NaN == NaN return false."); 28 } 29 </script>
关于【代码2-22】的分析如下:
第02行代码直接在浏览器控制台窗口中输出了特殊值NaN的内容;
第03行代码通过typeof运算符对特殊值NaN进行了操作,并在浏览器控制台窗口中输出运算后的结果;
第04~08行代码通过isNaN()函数方法判断特殊值NaN是否为非数值,并根据判断结果在浏览器控制台窗口中进行相应的输出;
第09~13行代码通过isNaN()函数方法判断数值123是否为非数值,并根据判断结果在浏览器控制台窗口中进行相应的输出;
第14~18行代码通过isNaN()函数方法判断字符串“123”是否为非数值,并根据判断结果在浏览器控制台窗口中进行相应的输出;
第19~23行代码通过isNaN()函数方法判断字符串“abc”是否为非数值,并根据判断结果在浏览器控制台窗口中进行相应的输出;
第24~28行代码通过if语句判断特殊值NaN自身是否为逻辑相等,并根据判断结果在浏览器控制台窗口中进行相应的输出。
页面效果如图2.22所示。第03行代码通过typeof运算符操作特殊值NaN后的结果为Number类型,这与NaN的定义是一致的。
第04~08行代码通过isNaN()函数方法判断特殊值NaN是否为非数值的结果为“true”,表示NaN为非数值;
第09~13行代码通过isNaN()函数方法判断数值123是否为非数值的结果为“false”,表示123不是非数值;
而第14~18行代码通过isNaN()函数方法判断字符串“123”是否为非数值的结果为“false”,表示“123”同样不是非数值;
第19~23行代码通过isNaN()函数方法判断字符串“abc”是否为非数值的结果为“true”,表示“abc”为非数值;
第24~28行代码通过if语句判断特殊值NaN自身是否为逻辑相等的结果为“false”,表示特殊值NaN与其自身逻辑不相等,这就是前文中提到的特殊值NaN的奇怪之处。
图2.22 Number类型特殊值(NaN)
下面,我们介绍ECMAScript语法中的第五种原始类型——String(字符串)。String类型与前几种原始类型的区别之处在于其是唯一没有固定大小的原始类型。我们可以用字符串存储0或更多的Unicode字符(Unicode是一种国际通用字符集标准,又称为统一字符编码)。
String类型字符串中的每个字符都有固定的位置,首字符从位置标记0开始,第二个字符在位置标记1处,依此类推。因此,字符串中的最后一个字符的位置标记一定是字符串的长度减1。
ECMAScript语法中规定String类型字符串是通过双引号(")或单引号(')来定义声明的,这与Java语言是有区别的,Java语言必须是使用双引号(")来定义声明字符串,而用单引号(')定义声明的仅仅是字符。由于ECMAScript语法中没有定义字符类型,所以定义声明字符串既可使用双引号("),也可以使用单引号(')。
下面,先看第一个关于String类型的代码示例(详见源代码ch02目录中ch02-js-string-a.html文件)。
【代码2-23】
01 <script type="text/javascript"> 02 var v_str_a = "Hello EcmaScript!"; 03 var v_str_b = "Hello 'EcmaScript!'"; 04 var v_str_c = 'Hello "EcmaScript!"'; 05 console.log(v_str_a); 06 console.log(v_str_b); 07 console.log(v_str_c); 08 </script>
关于【代码2-23】的分析如下:
第02~04行代码通过“var”关键字定义了三个变量(v_str_a、v_str_b、v_str_c),并初始化字符串。其中,第03行和第04行代码初始化的字符串中,演示如何在定义字符串时以嵌套方式使用双引号(")和单引号(');
第05~07行代码在浏览器控制台窗口中输出了三个变量(v_str_a、v_str_b、v_str_c)相应的内容。
页面效果如图2.23所示。如果想输出带有双引号(")或单引号(')的字符串,那么在定义字符串时必须以嵌套方式将双引号(")或单引号(')加进去。
图2.23 String原始类型(1)
下面,我们继续看第二个关于String类型的代码示例(详见源代码ch02目录中ch02-js-string-b.html文件)。
【代码2-24】
01 <script type="text/javascript"> 02 var v_str_a = "Hello"; 03 var v_str_b = "Ecma"; 04 var v_str_c = "Script"; 05 console.log(v_str_a + " " + v_str_b + v_str_c + "!"); 06 </script>
页面效果如图2.24所示。使用运算符“+”就可以有效地将字符串进行连接,比操作方式在具体设计中十分有用。
图2.24 String原始类型(2)
最后,看一下ECMAScript语法中定义的一些特殊字符串,详见表2-2,这些特殊字符串在某些特定环境下非常有用。
表2-2 ECMAScript特殊字符串
下面,就看一段使用String类型特殊字符串的代码示例(详见源代码ch02目录中ch02-js-string-c.html文件)。
【代码2-25】
01 <script type="text/javascript"> 02 var v_str_a = "Hello"; 03 var v_str_b = "Ecma"; 04 var v_str_c = "Script"; 05 console.log(v_str_a + "\b\'\n" + v_str_b + "\"\n\r" + v_str_c + "\t!\\"); 06 </script>
页面效果如图2.25所示。从图中可以看出,使用特殊字符串就可以实现空格、换行和添加标点符号的效果,这在具体设计中是非常实用的。
图2.25 String原始类型(3)
本小节介绍ECMAScript语法中获取字符串长度的方法。ECMAScript语法中规定通过String类型的“length”属性可以获取字符串的长度。
下面来看一个关于获取String类型字符串长度的代码示例(详见源代码ch02目录中ch02-js-string-length.html文件)。
【代码2-26】
01 <script type="text/javascript"> 02 var v_str = "Hello EcmaScript!"; 03 console.log(v_str.length); 04 var v_i = 123; 05 console.log(v_i.length); 06 var v_null = null; 07 console.log(v_null.length); 08 </script>
关于【代码2-26】的分析如下:
第02行代码通过“var”关键字定义了第一个变量(v_str),并初始化赋值一个字符串;
第03行代码通过length属性获取字符串变量(v_str)的长度,然后将操作后的结果在浏览器控制台窗口中进行了输出;
第04行代码通过“var”关键字定义了第二个变量(v_i),并初始化赋值一个整数数值;
第05行代试图通过length属性获取整数变量(v_i)的长度,然后将操作后的结果在浏览器控制台窗口中进行了输出。定义这行代码的目的就是想测试一下length属性是否对Number类型的变量有效;
第06行代码通过“var”关键字定义了第三个变量(v_null),并初始化赋值“null”原始值;
第07行代试图通过length属性获取变量(v_null)的长度,然后将操作后的结果在浏览器控制台窗口中进行了输出。同样,定义这行代码的目的也是想测试一下length属性是否对Null类型的变量有效。
页面效果如图2.26所示。length属性对于字符串有效,而对于Number类型数值和Null类型无效(即使可以使用length属性),这一点需要设计人员在使用length属性时注意。
图2.26 获取字符串长度