JavaScript基本概念——数据类型
What doesn't kill you makes you stronger.
ECMAScript数据类型
ECMAScript 中有5种简单(基本)数据类型:Undefined、Null、Boolean、Number和String。
ECMAScript 有一种复杂数据类型:Object,其本质是由一组无序的键值对组成的。
typeof操作符
用于检测给定变量或字面量的数据类型。可能返回下列某个字符串:
- "undefined"
- "boolean"
- "string"
- "number"
- "object"
- "function"
注意 typeof 是操作符,不是函数,因此其后的括号是可以省略的。
函数在 ECMAScript 中是对象,但是函数又有一些特殊属性,因此区分函数与其他对象是有必要的。
特别的,当 typeof 返回"object",不代表这个值是一定是对象,它也有可能是 null,因为 null 被认为是一个空的对象引用。
1.Undefined类型
此类型只有一个值:undefined。这个值在 ECMA-262 第 3 版被引入,用以区分空对象指针与未初始化的变量。
var message ;
相当于
var message = undefined;
对一个未声明的变量和一个声明但未赋值的变量,执行 typeof 操作符都返回"undefined"值。
未声明变量唯一能执行的操作是 typeof。
2.Null类型
此类型只有一个值:null。null 表示一个空对象指针,因此对 null 执行 typeof 操作符返回"object"。
如果你定义了一个变量准备用来保存对象,并且想知道该变量是否保存了对象,那你应该将该变量初始化为 null,而后你只要检查 null 值即可。
因为 undefined 是派生自 null,因此 ECMA-262 规定 null==undefined 总是返回 true。尽管它们相等,但它们的用途完全不同,我们在任何时候都没有必要的将一个变量的值显式设置为 undefined,但是某些情况下显式设置为 null 是有必要的。
3.Boolean类型
此类型只有两个值:true 和 false。因为 ECMAScript 中的一切都区分大小写,所以 True 和 False 都不是 Boolean值,只是普通的标识符(关键字、保留字、true、false、null 不能用作标识符)。
虽然 Boolean 类型的字面量只有两个,但是 ECMAScript 中所有类型的值都有与之等价的值,可以调用转型函数 Boolean() 将一个任意类型的值转换为对应的 Boolean 值。
数据类型 | 转换为 true | 转换为 false |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | ""(空字符串) |
Number | 任何非零数字值(含无穷大) | 0 和 NaN |
Object | 任何对象 | null |
Undefined | n/a(不适用,因为 Undefined 只有一个值) | undefined |
Null | n/a(不适用,因为 Null 只有一个值) | null |
4.Number类型
此类型使用 IEEE 754 格式来表示整数和浮点数值。
JavaScript 中的所有数字都存储为 64 位(8字节)浮点数。
JavaScript 不是类型语言。与许多其他编程语言不同,JavaScript 不定义不同类型的数字,比如整数、短整数、长整数、浮点数等等。
整数可以通过十进制,八进制和十六进制表示。其中八进制字面量的第一位必须是零,然后是八进制的数字序列(0-7),如果序列出现 8 或 9,则无视前导零当作十进制解析。八进制在严格模式下无效。
十六进制字面值的前两位必须是0X,然后是任何十六进制数(字母 A-F 不限大小写)。
在进行算术运算时,所有整数都会被转换成十进制数值。
浮点数值
所谓浮点数值,就是该数值中必须包含一个小数点,且小数点后至少有一位数字,小数点前面可以没有整数但不推荐这样写。
保存浮点数值所需内存空间是整数值的两倍,因此如果小数点后面没有有效数字,那么这个浮点数会被保存为整数。
极大或极小值用科学记数法表示(e不限大小写),如 3.125 e7。默认情况下,ECMAScript 会将小数点后带6个零以上的浮点数转为以科学记数法表示的数值。
浮点数值最高精度是17位小数,但计算精确度远远不如整数,所以永远不要测试某个特定的浮点数值(这是使用基于 IEEE 754 数值的浮点计算的语言的通病)。
数值范围
由于内存限制,ECMAScript 并不能保存所有数值,它能表示的最大数值保存在 Number.MAX_VALUE 中(通常是 1.7976931348623157e+308),最小数值保存在 Number.MIN_VALUE 中(通常是 5e-324)。
如果计算得到了超出数值范围的值,这个值将被自动转换成特殊的 Infinity 值(即负无穷 -Infinity 和正无穷 Infinity )。
Infinity 值无法继续参与计算。
可以使用 isFinite() 函数确定数值是否有穷。
NaN
NaN(Not a Number)是一个特殊的数值,用于表示一个本来要返回数值的操作数未返回数值的情况(从而避免抛出异常)。例如,ECMAScript 中数值除以非数值会返回 NaN,而其他语言则会因异常而停止代码运行。
NaN 有两个特点,第一是任何涉及 NaN 的操作都会返回 NaN,第二是 NaN 不等于任何值(包括 NaN 本身)。
依据这两个特点,ECMAScript 定义了 isNaN() 函数,用于确定传入参数是否不是数值(函数会尝试转换参数为数值,转换失败则返回 true)(当传入一个对象时,函数会先调用对象的 valueOf() 方法,若返回值不能转换为数值,则基于此返回值再调用 toString() 方法)。
数值转换
有三个函数将非数值转换为数值:Number()、parseInt()、parseFloat(),第一个可以用于任何数据类型,第二第三则专门把字符串转换为数值。
1. Number()
对于 Number() 函数,遵循以下规则:
- 如果是 Boolean 值,true 转为 1,false 转为 0
- 如果是数字值,不变
- 如果是 null 值,返回0
- 如果是 undefined,返回 NaN
- 如果是字符串,则遵循以下规则:
- 如果字符串中只包含数字(包括带正负号的情况),则将其转为十进制数字(忽略前导零)
- 如果字符串中只包含浮点数(包括带正负号的情况),则将其转为对应数字(忽略前导零)
- 如果字符串中只包含十六进制数,则将其转为对应十进制数字(忽略前导零)
- 如果字符串为空,则转为 0
- 如果字符串中包含除以上格式之外的字符,则转为NaN
- 如果是对象,则调用该对象的 valueOf() 方法,然后依据上面规则转换返回值,如果结果为 NaN,则调用对象的 toString() 方法,然后再次依照前面的规则转换返回的字符串
2. parseInt()
对于 parseInt() 函数,它在转换字符串的时候,更多的是看其是否符合数值模式。
它会忽略字符串前面的空格。
如果第一个非空格字符不是正负号或者数字,它会返回 NaN(这意味着它对空字符串也会返回 NaN,而 Number() 会返回 0)。
parseInt() 会从第一个非空格字符开始解析,直到它遇到了一个非数字字符(包括小数点)或者全部解析完成。
如果字符串以 0 或者 0x 开头且后跟数字,parseInt() 也能正确识别为对应进制数值。
在 ECMAScript 3 JavaScript 引擎中,"077"被认为是八进制字面量,而在 ECMASript 5 JavaScript 引擎中,parseInt() 不再具备解析八进制的能力,因此前导的零会被忽略,即使在非严格模式依然如此。
parseInt() 允许提供第二个参数以指定进制,为了避免解析出错,无论什么情况下都应该明确指定进制数。
"-0xf"使用 Number() 得到的结果是 NaN,而使用 parseInt() 得到的结果是 -15,可见 Number() 函数不够合理,因此处理整数的时候更常用的是 parseInt() 函数。
3. parseFloat()
parseFloat() 也是从第一个字符开始解析字符,直到字符串末尾或者遇见无效的浮点数字字符(第一个小数点是有效字符)。
parseFloat() 始终会忽略前导零。
parseFloat() 只解析十进制值,因此解析十六进制数的结果始终是0,同样的它也没有第二个参数用于指定进制。
特别的,如果字符串包含的是一个可解析为整数的数,parseFloat() 会返回整数。
5.String类型
String 类型用于表示字符串(零个或多个 16 位 Unicode 字符组成的字符序列)。
字符串可以由单引号或双引号表示(PHP 中单双引号的解释方式不同,但 ECMAScript 相同)。
字符字面量
String 类型包含一些特殊的字面量,也叫转义字符:
字面量 | 含义 |
---|---|
\n | 换行 |
\t | 制表(tab) |
\b | 退格(退格\b 无法输出到屏幕上,只有输出到打印机上或者输出至文件才会起作用) |
\r | 回车(同上) |
\f | 换页 |
\\ |
斜杠 |
\' |
单引号 |
\" |
双引号 |
\xnn |
以十六进制码 nn 表示的一个 ASCII 字符(n 为 0~F),如"\x41",对应 ASCII 的第 65个 字母"A" |
\unnnn |
以十六进制码 nnnn 表示的一个 Unicode 字符(n 为 0~F),如"\u4e2d",对应 Unicode 的字符"中" |
任何字符串的长度都可以通过访问其 length 属性获得。
字符串包含多字节字符时,length 属性可能不会精确的返回字符串中的字符数(不同的编码里面汉字长度不同,GBK 编码一个汉字占两个字节,UTF-8 编码汉字通常占三个字节,扩展 B 区以后的汉字占四个字节)。
字符串的特点
ECMAScript 中字符串是不可变的(Java 也如此),一旦创建,它的值就不能改变。
例如,要实现字符串拼接操作,先要创建一个长度合适的新字符串,创建待拼接的字符串,然后往新字符串中填充原来的和待拼接的字符串,最后销毁原来的字符串和待拼接的字符串。这些都是后台完成的,所以在一些旧版本浏览器中,拼接字符串的速度很慢。
转换为字符串
有三种转换任意值为字符串的方法:
- 第一种是调用其 toString() 方法(null 和 undefined 没有这个方法),如果该值为数值,那么这个方法可以传入一个参数以作为输出数值的进制数;
- 第二种方法是调用转型函数 String(),这个函数能处理转换值为 null 或者 undefined 的情况(返回其字面量),但不能传入参数;
- 第三种方法是使用加号操作符,将该值与一个空字符串相加。
6.Object类型
ECMAScript 中的对象其实就是一组数据和功能的集合。对象可以通过执行 new 操作符 + 创建的对象类型名来创建。例如:
var obj = new Object();
在 ECMAScript 中,如果不给构造函数传参数,则可以省略圆括号(不建议这样做)。
在 ECMAScript 中,Object 类型是其所有实例的基础(就像在 Java 中 java.lang.Object 是所有对象的基础一样)。每个 Object 的实例都具有下列属性和方法:
- constructor:保存用于创建当前对象的函数(构造函数),例如 Object()
- hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中是否存在(注意是实例而非原型),参数必须是字符串,例如 obj.hasOwnproperty("name")
- isPrototypeOf(object):用于检查传入的对象是否是当前对象的原型
- propertyIsEnumerable(propertyName):用于检查给定的属性是否能枚举(使用 for-in 语句),参数必须是字符串
- toLocaleString():以当地的语言返回对象的字符串表示
- toString():返回对象的字符串表示
- valueOf():返回对象最合适的原始值(字符串、数值或布尔值)表示
toString() 和 valueOf() 一般都由 JavaScript 隐式调用,在数值运算中优先调用 valueOf(),在字符串运算中优先调用 toString()。
在出现"+"操作符的情况下 JavaScript 默认两边的值是 Number,所以会优先调用 valueOf()。
ECMA-262 中的对象的行为不一定适用于 JavaScript(ECMAScript 只是 JavaScript 的核心)中的其他对象。
例如,浏览器环境中的 BOM 和 DOM 对象(都是由宿主定义和实现的宿主对象),就不完全适用 ECMA-262 中的对象的行为。这是因为 ECMA-262 不负责定义宿主对象,所以宿主对象不一定会继承 Object 对象。