一、初识数据类型
1. 概要
JavaScript 语言的每一个值,都属于某一种数据类型。JavaScript 的数据类型,共有七种。
数值(number):整数和小数(比如1和3.14);
字符串(string):文本(比如Hello World);
布尔值(boolean):表示真伪的两个特殊值,即true(真)和false(假);
undefined:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值;
null:表示空值,即此处的值为空;
对象(object):各种值组成的集合;
Symbol类型 :不介绍。
对象是最复杂的数据类型,又可以分成三个子类型。
狭义的对象(object)
数组(array)
函数(function)
2. typeof 运算符
由于ECMAScript是松散型,JavaScript 有三种方法,可以确定一个值到底是什么类型。
typeof运算符;
instanceof运算符;
Object.prototype.toString方法。
用typeof检测变量可能返回以下某个字符串。
null开始为Object类型的一个数据,后来独立为一种数据类型,为了兼容以前的代码,typeof null返回object就没法改变了。
二、数据类型详解
1. null 和 undefined
1.1 概述
null表示‘空值’,undefined表示‘未定义’。
1.2 用法和含义
null表示‘空值’,调用函数时,某个参数未设置任何值,这时就可以传入null,表示该参数为空。比如,某个函数接受引擎抛出的错误作为参数,如果运行过程中未出错,那么这个参数就会传入null,表示未发生错误。
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
2. 布尔值
布尔值代表“真”和“假”两个状态。“真”用关键字true表示,“假”用关键字false表示。
3. 数值
3.1 概述
i. 浮点数
JavaScript 语言的底层没有整数,所有数字都是以64位浮点数形式储存;所以,1与1.0是同一个数;某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,然后再进行运算。
由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
0.1 + 0.2 === 0.3
// false
0.3 / 0.1
// 2.9999999999999996
(0.3 - 0.2) === (0.2 - 0.1)
// false
ii. 数值精度
根据国际标准 IEEE 754,JavaScript 浮点数的64个二进制位,从最左边开始,是这样组成的。
第1位:符号位,0表示正数,1表示负数;
第2位到第12位(共11位):指数部分;
第13位到第64位(共52位):小数部分(即有效数字)。
简单的法则就是,JavaScript 对15位的十进制数都可以精确处理。
iii. 数值范围
JavaScript 能够表示的数值范围为(21024,2-1023),超出这个范围的数无法表示。
如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,即 JavaScript 无法表示这么大的数,这时就会返回Infinity。
如果一个数小于等于2的-1075次方(指数部分最小值-1023,再加上小数部分的52位),那么就会发生为“负向溢出”,即 JavaScript 无法表示这么小的数,这时会直接返回0。
var x = 0.5;
for(var i = 0; i < 25; i++) {
x = x * x;
}
x // 0
3.2 普通数值
i. 普通数值的表示法有进制表示和科学计数
- 科学计数法允许字母e或E的后面,跟着一个整数,表示这个数值的指数部分。
- 进制表示有二进制、八进制、十进制、十六进制数值,前缀分别0B、0O、无前缀、0X,例如:0B10000、0O20、16、0X10为分别使用二、八、十、十六进制表示同一数值。
ii. 普通数值的自动转换
JavaScript 会自动将数值转为科学计数法表示。
- 小数点后的零多于5个;
- 小数点前的数字多于21位。
JavaScript 内部会自动将八进制、十六进制、二进制转为十进制,数字或字母不匹配进制将会报错。
ES5普通模式,在有前导0的数值会被视为八进制,但是如果前导0后面有数字8和9,则该数值被视为十进制。
3.3 特殊数值
i.正零和负零
正零和负零都会被当作正常的0,唯一有区别的场合是当+0或-0作为分母,如1 / +0,1 / -0,0 / 0 返回的值,分别得到+Infinity,-Infinity,NaN。
ii. NaN
- 含义:NaN是数据类型属于Number的非数值;
- 运算规则:NaN不等于任何值,包括它本身,NaN与任何数(包括它自己)的运算,得到的都是NaN。
iii. Infinity
由于数值正向溢出(overflow)、负向溢出(underflow)和被0除,JavaScript都不报错,而是返回Infinity,所以单纯的数学运算几乎没有可能抛出错误。
Infinity + Infinity // Infinity
Infinity * Infinity // Infinity
Infinity - Infinity // NaN
Infinity / Infinity // NaN
0 * Infinity // NaN
0 / Infinity // 0
Infinity / 0 // Infinity
null * Infinity // NaN
null / Infinity // 0
Infinity / null // Infinity
undefined + Infinity // NaN
undefined - Infinity // NaN
undefined * Infinity // NaN
undefined / Infinity // NaN
Infinity / undefined // NaN
Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN),Infinity与NaN比较,总是返回false。
3.4 特殊数值判断方法
i. isNaN()
isNaN方法可以用来判断一个值是否为NaN,只对数值有效,如果传入其他值,会被Number函数先转成数值。
ii. isFinite()
除了Infinity、-Infinity、NaN和undefined这几个值会返回false,isFinite对于其他的数值都会返回true。
4. 字符串
4.1 概述
字符串就是零个或多个排在一起的字符,放在单引号或双引号之中,默认只能写在一行内,ES6中可使用反引号(``)替代单双引号,让字符串写在多行。
JavaScript 的单位字符长度固定为16位长度,只能以2个字节的UTF-16格式储存,所以处理的时候,JavaScript 返回的字符串长度可能是不正确的。
4.2 转义
需要用反斜杠转义的特殊字符,主要有下面这些,若前面加反斜杠没有特殊含义,反斜杠会被自动省略。
- \0 :null(\u0000)
- \b :后退键(\u0008)
- \f :换页符(\u000C)
- \n :换行符(\u000A)
- \r :回车键(\u000D)
- \t :制表符(\u0009)
- \v :垂直制表符(\u000B)
- \' :单引号(\u0027)
- \" :双引号(\u0022)
- \\ :反斜杠(\u005C)
- \HHH (三个八进制数)
- \xHH (两个十六进制数)
- \uXXXX (四个八进制数)
console.log('1\n2')
// 1
// 2
'\a'
// "a"
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
4.2 字符串方法
- 使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)
- length属性返回字符串的长度
var s = 'hello';
s[0] // "h"
// 直接对字符串使用方括号运算符
'hello'[1] // "e"
s.length // 5
4.3 Base64 转码
文本里面包含一些不可打印的符号,比如 ASCII 码0到31的符号都无法打印出来,这时可以使用 Base64 编码,将它们转成可以打印的字符。另一个场景是,有时需要以文本格式传递二进制数据,那么也可以使用 Base64 编码。
所谓 Base64 就是一种编码方法,可以将任意值转成0~9、A~Z、a-z、+和/这64个字符组成的可打印字符。使用它的主要目的,不是为了加密,而是为了不出现特殊字符,简化程序的处理。
i. JavaScript 原生提供两个 Base64 相关的方法。
- btoa():ASCII码字符转为 Base64 编码;
- atob():Base64 编码转为原来的值。
ii. 非ASCII码字符转为Base64编码,必须中间插入一个转码环节。
function b64Encode(str) {
return btoa(encodeURIComponent(str));
}
function b64Decode(str) {
return decodeURIComponent(atob(str));
}
b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"
5. 对象
5.1 概述
通常,数值、字符串、布尔值这三种类型,合称为不能再细分的原始类型,对象类型往往是由多个原始类型的值的组成,可称为合成类型。
对象类型的组成部分的本质是无序键值对,‘键名’都是字符串,也称为属性,当为合法标识符时,则字符串引号可省略;‘键值’可以是任何数据类型,也可为函数。
5.2 表达式还是语句
如果没有圆括号,eval将其理解为一个代码块;加上圆括号以后,就理解成一个对象。
eval('{foo: 123}') // 123
eval('({foo: 123})') // {foo: 123}
5.3 对象的引用
如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。
5.4 属性操作
i. 读取属性
点运算符和方括号运算符读取对象属性,若方括号运算符内标识符无引号,则标识符表示一变量,而非字符串;
查看一个对象本身的所有属性,可以使用Object.keys方法;
var obj = {
key1: 1,
key2: 2
};
Object.keys(obj);
// ['key1', 'key2']
- for...in循环用来遍历一个对象的全部属性。
它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
它不仅遍历对象自身的属性,还遍历继承的属性。
var obj = {a: 1, b: 2, c: 3};
for (var i in obj) {
console.log(obj[i]);
}
// 1
// 2
// 3
- in运算符,用于检查对象是否包含某个属性(注意,检查的是键名,不是键值),如果包含就返回true,否则返回false。
ii. 增加属性
允许属性的“后绑定”,使用点运算符和方括号运算符来读取“后绑定”对象属性。
iii. 删除属性
delete命令用于删除对象的属性,删除成功后返回true。
三、数据转换
1. 强制转换
1.1 Number()、parseInt()、parseFloat()
i. 原始类型值
对于Number(),数值和字符串整体转换为数值,基本上只要有一个字符无法转成数值,整个字符串就会被转为NaN。布尔值true和false转换为1和0,undefined和null转换为NaN和0,
对于parseInt(),将参数(不能识别符合科学计数法字符串)转为字符串,返回字符串有效位的整数,无有效位返回NaN。
parseInt(字符串,进制)
- 字符串的进制由进制参数和字符串首位决定,进制参数会被自动转为一个整数(2到36之间),进制参数是0、undefined和null,则直接忽略,返回该值对应的十进制数,字符串首位是OX,则默认进制参数为十六进制,O为首字符串参数,0将会被忽略,则默认进制参数为十进制;
- 如果字符串包含对于指定进制无意义的字符,则从最高位开始,只返回可以转换的数值。如果最高位无法转换,则直接返回NaN;
对于parseFloat(),将参数(能识别符合科学计数法字符串)转为字符串,返回字符串有效位的小数,无有效位返回NaN;
parseInt,parseFloat和Number函数都会自动过滤一个字符串前导和后缀的空格。
parseInt('\t\v\r12.34\n') // 12
Number('\t\v\r12.34\n') // 12.34
对于布尔值、null和undefined的转换值区别如下。
数值转换 | true | false | null | undefined |
---|---|---|---|---|
Number() | 1 | 0 | 0 | NaN |
parseInt() | NaN | NaN | NaN | NaN |
parseFloat() | NaN | NAN | NaN | NaN |
ii. 对象
Number()、parseInt()、parseFloat()会将对象转换为原始数据类型,再使用Number函数将原始数据类型转为数值。
对象转换为原始数据类型过程具体为先调用对象自身的valueOf方法,使对象能返回原始类型的值,否则改为调用对象自身的toString方法,返回原始类型的值,如果toString方法返回的还是对象,就报错。
1.2 String()、toString()
i. 原始类型的值
String()函数和toString()方法功能范围:
数值:转为相应的字符串,额外地,toString()方法可传入二、八、十六数值或字符串的进制参数;
字符串:转换后还是原来的值;
布尔值:true转为字符串"true",false转为字符串"false";
undefined:String()函数转为字符串"undefined",但无toString()方法;
null:String()函数转为字符串"null",但无toString()方法。
ii. 对象
String()会将对象转换为原始类型的值,和Number()相反,String()先调用toString,后调用valueOf。
String({a: 1}) // "[object Object]"
String([1, 2, 3]) // "1,2,3"
1.3 Boolean()
除了undefined,null,false,0,NaN,""或''(空字符串)六个值被转为false,其他都是true,包括空数组([])和空对象({})。
2. 自动转换
自动转换的规则是:预期是布尔值、数值、字符串的地方,会分别自动调用Boolean、Number和String函数进行转换。
2.1 自动转换为布尔值
i. 下列运算符会返回布尔值;
两元逻辑运算符: && (And),|| (Or);
前置逻辑运算符: ! (Not),!!(等价Boolean());
相等运算符:===,!==,==,!=;
比较运算符:>,>=,<,<=。
ii. 程序流程的控制里,判断条件会自动会返回布尔值。
if ([]) {
console.log('true');
}
// true
if ({}) {
console.log('true');
}
// true
2.2 自动转换为字符串
主要发生在字符串的加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。
2.3 自动转换为数值
除了加法运算符(+)有可能把运算子转为字符串,其他运算符都会把两侧运算子自动转成数值。