常用数据类型#
ECMAScript有6种简单的数据类型(原始类型):Undefined,Null,Boolean,Number,String和Symbol(ES6新增Symbol类型的值,在此不会过多涉及)
此外还有一种复杂的数据类型:Object
在ECMAScript中无法定义自己的数据类型,所有值都必须采用以上七种数据类型之一来进行表示,好在ECMAScript数据类型比较灵活,一种数据类型可以当做多种数据类型进行使用
其中,数值、字符串、布尔值这三种类型合称为原始类型的值,即这三种类型是最基本的数据类型,无法继续细分。对象则称为合成类型的值,因为一个对象往往是多个原始类型的值所组成,可以看做一个存放各种值的容器。至于undefined和null,一般将他们视为两个特殊的值。
typeof 操作符##
一种用来确定任意变量的数据类型的手段,对一个变量使用typeof操作符会返回下列字符串其一:
“undefined”表示值未定义
“boolean”表示值为布尔值
“string”表示值为字符串
“number”表示值为数字
“object”表示值为对象(不是函数)或null
“function”表示值为函数
“symbol”表示值为符号
例如:
let message = "some string";
console.log(typeof message); // string
console.log(typeof (message)); // string
console.log(95); // number
Undefined 类型##
Undefined数据类型只有一个值,即undefined。当你使用了var或者let声明了一个变量但没有对其进行初始化时,就相当于给这个变量赋值了undefined:
let message;
console.log(message); //undefined
console.log(message == undefined); // true
默认情况下,任何未经过初始化的变量都会自动获得undefined值
需要注意的是,对未初始化和未定义的变量调用typeof操作符,返回的值都是undefined:
let message
console.log(typeof message); // undefined
console.log(typeof age); // undefined
因此建议在声明变量时一定要对其进行初始化,只有这样你才会知道当返回undefined时,这是一个未声明的变量,而不是没有对其进行初始化
常见返回undefined值的场景:
// 变量声明了,但没有赋值
var i;
i // undefined
// 调用函数时,应该提供的参数没有提供,该参数等于 undefined
function f(x) {
return x;
}
f() // undefined
// 对象没有赋值的属性
var o = new Object();
o.p // undefined
// 函数没有返回值时,默认返回 undefined
function f() {}
f() // undefined
Null 类型##
同样,该类型只有一个值null。逻辑上讲,null值表示一个空对象指针,所以当对null调用typeof操作符时,返回的数据类型为object
任何时候,当你定义一个对象,而又恰好没有需要存入对象的数据,那么请用null来暂时填补它
undefined是由null派生而来,因此ECMA-262将他们定义为表面上相等:
console.log(null == undefined); // true
然而即便是undefined和null有派生关系,但它们的用途却完全不一样,一般情况下我们不会主动给变量赋值为undefined。然而对于对象来讲,用null来填充它有时候却是相当必要的
Boolean 类型##
这种数据类型只有两个字面上的值:true 和 false
需要强调的是:这两个布尔值是不等同于数字1和0的
虽然布尔值只有两个,但是ECMAScript可以将其它数据类型转换为布尔值,具体的转换规则如下所示:
当以下数据类型为如下值时,转换为布尔值为true:
Boolean——true
String——非空字符串
Number——非零数值(包括无穷值)
Object——任意对象
Undefined——N/A(不存在)
当以下数据类型为如下值时,转换为布尔值为false:
Boolean——false
String——""(空字符串)
Number——0、NaN
Object——null
Undefined——undefined
这种转换方式常用于if等流控制语句:
let message = "hello world !"
if(message){
console.log("value is true.")
}
Number 类型##
八进制、十进制和十六进制的表示方法:
十进制是最基本的数值字面量,直接写出来即可:
let intNum = 55; // 十进制整数
对于八进制字面量而言,第一个数字必须是零(0),然后后面才是相应的八进制数字(0-7),如果字面量中包含了超出给定有效范围的数值,或者前缀不是0,则会当成普通的十进制数来处理:
let octalNum1 = 070; // 56(八进制)
let octalNum2 = 079; // 79(被当成普通十进制处理)
let octalNum3 = 08; // 8 (同上)
需要注意的是,八进制字面量在严格模式下是无效的,ES6中规定八进制数的表示方法的前缀为0o,如:
let octalNum1 = 0o253; // 171(八进制)
let octalNum2 = 0o115; // 77(同上)
let octalNum3 = 0o632; // 410 (同上)
对于十六进制字面量而言,前缀必须为0x,然后才是十六进制数字(0-F),十六进制中的字母大小写均可,例如:
let hexNum1 = 0xA1; // 161(十六进制)
let hexNum2 = 0xfff; // 4095(同上)
使用八进制和十六进制创建的数值在所有数学操作中都被视为十进制数值
浮点值
若要定义浮点值,数值当中必须包含有小数点,且小数点后面至少要有一个数字,虽然小数点前面的数字可有可无,但还是推荐加上:
let floatNum1 = 1.1; // 1.1
let floatNum2 = 0.1; // 0.1
let floatNum3 = .1; // 0.1(不推荐)
因为浮点值的存储空间会是整数值的两倍,所以ECMAScript总是想办法将值转换为整数,若小数点后面没有数字,则会自动转化为整数来处理;类似的,如果数值本身为整数,只是小数点后面跟着0,也会被转化为整数来处理:
let float1 = 1.; // 小数点后面没用数字,当成整数1来处理
let float2 = 1.0; // 本身是整数只是表示为小数,也当成整数来处理
科学计数法
如果要用科学计数法表示一个整数,则要求是一个数值(整数或浮点值),后面跟一个大写或者小写的字母e,再加上一个要乘的10的多少次幂:
let num1 = 3.1275e7; // 等于31275000
同理,科学计数法也可以用来表示数值很小的值:
let num2 = 123e-5; // 等于0.00123
虽然浮点值精度最高可以达到17位小数,但是在算数计算中远不如整数那么精确,比如:
0.1 + 0.2 ; // 0.30000000000000004(答案不是0.3)
由于这种微小的舍入错误,导致实际操作时很难对浮点值进行测试,比如:
let a = 0.1;
let b = 0.2;
if(a + b == 0.3){
console.log('you got 0.3.'); // 这种测试是没有任何意义的
}
因此我的建议是:永远不要测试某个特定的浮点值!
(注意:这种错误并非ECMAScript独有,其它使用IEEE754数值的语言也都有这个问题)
数值的范围:
由于内存限制,ECMAScript并不能支持这个世界上所有的值,实际上,它所能表示的值有一个限制范围:ECMAScript所能表示的最小值存储在Number.MIN_VALUE中,这个值一般是5e-324;最大值保存在Number.MAX_VALUE中,这个值一般是1.7976931348623157e+308
如果某个计算值超出了JavaScript所能表示的范围,那么这个值将会自动转换为一个特殊的Infinity值,其中正无穷表示为Infinity,负无穷表示为-Infinity:
let res = Number.MAX_VALUE + Number.MAX_VALUE;
console.log(res); // Infinity
NaN
这是一个特殊的数值,意为“不是数值(not a number)”,用于表示本来会返回数值的操作失败了(并不是抛出错误)。比方说用0除其它任何数字在其它语言中通常会导致错误,以至于代码无法运行,但是在ECMAScript中,0、+0或-0相除会返回NaN:
0 / 0 ; // NaN
若是非零数值除0,则会返回Infinity或-Infinity:
5 / 0 ; // Infinity
NaN有几个特殊的属性:首先涉及NaN的操作始终都会返回NaN,其次NaN不等于包含NaN在内的任何值,比如:
NaN == NaN; // false
ECMAScript提供了一个isNaN()函数,该函数可以接受一个参数,可以使任意数据类型,然后来判断这个参数是否是“不是数值”。参数在传入isNaN()函数后,该函数会尝试将它转换为数值。任何不能转换为数值的参数都会导致这个函数返回true,比如:
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false
console.log(isNaN('10')); // false,可以转换为数值10
console.log(isNaN('age')); // true
console.log(isNaN(true)); // false,可以转换为数值1
数值转换:
有三个函数可以将非数值转换为数值:Number()、parseInt()、parseFloat()
Number()函数的转换基于以下规则:
- 布尔值:true转换为1,false转换为0
- 数值:直接返回
- null:返回为0
- undefined:返回为NaN
- 字符串:应用以下规则:
-- 如果字符串包含数字字符,包括数字字符前带有加、减号的情况,则转换为一个十进制数值(忽略前面的0)
-- 如果字符串包含有效的浮点值格式,则转换为相应的浮点值(忽略前面的0)
-- 如果字符串包含有效的十六进制格式,如0xff,则会转换为与之对应的十进制数值
-- 如果是空字符串,返回0
-- 如果字符串包含除上述情况以外的其它字符,返回NaN
举例:
Number('hello world 123'); // NaN
Number(''); // 0
Number('000000111'); // 111
Number(true) // 1
考虑到Number()函数转换字符串时相对复杂并且反常规,大多数时候我们都用parseInt()来得到整数
首先字符串前面的空格会被忽略,从第一个非空格字符开始,如果不是数值字符或者加减号,则立即返回NaN;如果第一个字符是数值字符或者加减号,则会继续以此检测每个字符,直到字符串末尾,或碰到非数字字符:
parseInt(' 000245688aaadsdf'); // 245688(前面空格和0被完美的忽略掉了)
parseInt('3.14159'); // 3(小数点为非数字字符,其后的数字也被忽略掉)
parseInt(''); // NaN
parseInt('0xff'); // 255(十六进制会被转换为十进制)
parseInt()接受第二个参数,用来指定底数进行解析转化:
parseInt('100',2); // 4(按二进制解析)
parseInt('100',8); // 64(按八进制解析)
parseInt('100',10); // 100(按十进制解析)
parseInt('100',16); // 256(按十六进制解析)
因为如果不传入底数就相当于让parseInt()函数自己解析,因此为了避免出错,建议始终传入第二个参数
parseFloat()函数的工作方式与parseInt()函数类似,都是从头开始检测字符,直到字符串末尾。相比于parseInt()的唯一区别就是其只能解析十进制数值,因此无法传入第二个参数:
parseFloat(' 0005646.7859aposdaj'); //5646.7859(始终忽略字符串开头的0)
parseFloat(' 000.25456'); //0.25456(小数点前面的0会保留)
parseFloat('005.6846.456899'); //5.6846(只保留最左边小数点的小数)
parseFloat(''); //NaN
parseFloat('3.14e12') //3140000000000(适用于科学计数法)