# js基础数据类型详解
JavaScript 有 7 种基础数据类型(也称为原始类型),String、Number、BigInt、Boolean、Null、Undefined 和 Symbol。
# 1、String 字符串
String(字符串)数据类型表示零或多个 16 位 Unicode 字符序列。字符串可以使用双引号(")、单引号(')或反引号(`)标示,因此下面的代码都是合法的:
let firstName = "John";
let lastName = 'Jacob';
let lastName = `Jingleheimerschmidt`;
2
3
注意:以某种引号作为字符串开头,必须仍然以该种引号作为字符串结尾。
let firstName = 'Nicholas"; // 语法错误:开头和结尾的引号必须是同一种
# 1.1 字符字面量
字符串数据类型包含一些字符字面量,用于表示非打印字符或有其他用途的字符,如下表所示:
字面量 | 含义 |
---|---|
\n | 换行 |
\t | 制表 |
\b | 退格 |
\r | 回车 |
\f | 换页 |
\\ | 反斜杠 |
\' | 单引号 |
\" | 双引号 |
\` | 反引号 |
\xnn | 以十六进制编码 nn 表示的字符(其中 n 是十六进制数字 0~F),例如 \x41 等于 "A" |
\unnn | 以十六进制编码 nnnn 表示的 Unicode 字符(其中 n 是十六进制数字 0~F),例如 \u03a3 等于希腊字符 "Σ" |
# 1.2 字符串的特点
ECMAScript 中的字符串是不可变的(immutable),意思是一旦创建,它们的值就不能变了。要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量,如下所示:
let lang = "Java";
lang = lang + "Script";
2
# 1.3 转换为字符串
toString() 方法可见于数值、布尔值、对象和字符串值。该方法只是简单地返回自身的一个副本。) null 和 undefined 值没有 toString() 方法。
默认情况下, toString() 返回数值的十进制字符串表示。而通过传入参数,可以得到数值的二进制、八进制、十六进制,或者其他任何有效基数的字符串表示
如果你不确定一个值是不是 null 或 undefined ,可以使用 String() 转型函数,它始终会返回表示相应类型值的字符串。 String() 函数遵循如下规则。
- 如果值有 toString() 方法,则调用该方法(不传参数)并返回结果。
- 如果值是 null ,返回 "null" 。
- 如果值是 undefined ,返回 "undefined" 。
# 1.4 模板字面量
ES6 新增了使用模板字面量定义字符串的能力。与使用单引号或双引号不同,模板字面量保留换行字符,可以跨行定义字符串:
let myMultiLineTemplateLiteral = `first line
second line`;
2
# 1.5 字符串插值
模板字面量不是字符串,而是一种特殊的 JavaScript 句法表达式,只不过求值后得到的是字符串。字符串插值通过在 ${} 中使用一个 JavaScript 表达式实现:
let interpolatedTemplateLiteral =
`${ value } to the ${ exponent } power is ${ value * value }`;
2
所有插入的值都会使用 toString() 强制转型为字符串,而且任何 JavaScript 表达式都可以用于插值。嵌套的模板字符串无须转义
# 1.6 模板字面量标签函数
模板字面量也支持定义标签函数(tag function),而通过标签函数可以自定义插值行为。
let num1 = 6;
let num2 = 7;
function foo (a, b, c, d) {
console.log(a);
console.log(b);
console.log(c);
console.log(d)
}
foo`num1${num1}+num2${num2}=${num1 + num2}`
2
3
4
5
6
7
8
9
10
11
因为表达式参数的数量是可变的,所以通常应该使用剩余操作符(rest operator)将它们收集到一个数组中:
function foo (a, ...b) {
console.log(a);
for(const item of b) {
console.log(item);
}
}
let a = 6;
let b = 9;
function zipTag(strings, ...expressions) {
return strings[0] +
expressions.map((e, i) => `${e}${strings[i + 1]}`)
.join('');
}
let untaggedResult = `${ a } + ${ b } = ${ a + b }`;
let taggedResult = zipTag`${ a } + ${ b } = ${ a + b }`;
console.log(untaggedResult); // "6 + 9 = 15"
console.log(taggedResult); // "6 + 9 = 15"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1.7 原始字符串
使用模板字面量也可以直接获取原始的模板字面量内容(如换行符或 Unicode 字符),而不是被转换后的字符表示。为此,可以使用默认的 String.raw 标签函数:
// Unicode 示例
// \u00A9 是版权符号
console.log(`\u00A9`); // ©
console.log(String.raw`\u00A9`); // \u00A9
2
3
4
# 2、Number 数值
Number 类型使用 IEEE 754 格式表示整数和浮点值(在某些语言中也叫双精度值)。不同的数值类型相应地也有不同的数值字面量格式。
最基本的数值字面量格式是十进制整数,直接写出来即可:
let intNum = 55; // 整数
# 2.1 浮点值
要定义浮点值,数值中必须包含小数点,而且小数点后面必须至少有一个数字。虽然小数点前面不是必须有整数,但推荐加上。下面是几个例子:
let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 = .1; // 有效,但不推荐
2
3
因为存储浮点值使用的内存空间是存储整数值的两倍,所以 ECMAScript 总是想方设法把值转换为整数。在小数点后面没有数字的情况下,数值就会变成整数。类似地,如果数值本身就是整数,只是小数点后面跟着 0(如 1.0),那它也会被转换为整数,如下例所示:
let floatNum1 = 1.; // 小数点后面没有数字,当成整数 1 处理
let floatNum2 = 10.0; // 小数点后面是零,当成整数 10 处理
2
对于非常大或非常小的数值,浮点值可以用科学记数法来表示。科学记数法用于表示一个应该乘以10 的给定次幂的数值。ECMAScript 中科学记数法的格式要求是一个数值(整数或浮点数)后跟一个大写或小写的字母 e,再加上一个要乘的 10 的多少次幂。比如:
let floatNum1 = 3.125e7; // 等于 31250000
let floatNum2 = 3e-17; // 等于 0.000 000 000 000 000 03
let floatNum3 = 3e-7; // 等于 0.000 000 3
2
3
浮点值的精确度最高可达 17 位小数,但在算术计算中远不如整数精确。例如,0.1 加 0.2 得到的不是 0.3,而是 0.300 000 000 000 000 04。由于这种微小的舍入错误,导致很难测试特定的浮点值。
比如下面的例子:
if (a + b == 0.3) { // 别这么干!
console.log("You got 0.3.");
}
2
3
这里检测两个数值之和是否等于 0.3。如果两个数值分别是 0.05 和 0.25,或者 0.15 和 0.15,那没问题。但如果是 0.1 和 0.2,如前所述,测试将失败。因此永远不要测试某个特定的浮点值。
之所以存在这种舍入错误,是因为使用了 IEEE 754 数值,这种错误并非 ECMAScript 所独有。其他使用相同格式的语言也有这个问题。
解决办法:
(1)换成别的数字
(0.1*10+0.2*10)/10 === 0.3
(2)保留小数位数
parseFloat((0.1+0.2).toFixed(10)) === 0.3
# 2.2 值的范围
由于内存的限制,ECMAScript 并不支持表示这个世界上的所有数值。ECMAScript 可以表示的最小数值保存在 Number.MIN_VALUE 中,这个值在多数浏览器中是 5e324;可以表示的最大数值保存在Number.MAX_VALUE 中,这个值在多数浏览器中是 1.797 693 134 862 315 7e+308。
如果某个计算得到的数值结果超出了 JavaScript 可以表示的范围,那么这个数值会被自动转换为一个特殊的 Infinity(无穷)值。任何无法表示的负数以-Infinity(负无穷大)表示,任何无法表示的正数以 Infinity(正无穷大)表示。
如果计算返回正 Infinity 或负 Infinity,则该值将不能再进一步用于任何计算。这是因为Infinity 没有可用于计算的数值表示形式。要确定一个值是不是有限大(即介于 JavaScript 能表示的最小值和最大值之间),可以使用 isFinite()函数。
let result = Number.MAX_VALUE + Number.MAX_VALUE;
console.log(isFinite(result)); // false
2
# 2.3 NaN
有一个特殊的数值叫 NaN,意思是“不是数值”(Not a Number),用于表示本来要返回数值的操作失败了(而不是抛出错误)。比如,用 0 除任意数值在其他语言中通常都会导致错误,从而中止代码执行。但在 ECMAScript 中,0、+0 或0 相除会返回 NaN:
console.log(0/0); // NaN
console.log(-0/+0); // NaN
2
如果分子是非 0 值,分母是有符号 0 或无符号 0,则会返回 Infinity 或-Infinity:
console.log(5/0); // Infinity
console.log(5/-0); // -Infinity
2
NaN 不等于包括 NaN 在内的任何值。
console.log(NaN == NaN); // false
为此,ECMAScript 提供了 isNaN() 函数。该函数接收一个参数,可以是任意数据类型,然后判断这个参数是否“不是数值”。
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false,10 是数值
console.log(isNaN("10")); // false,可以转换为数值 10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值 1
2
3
4
5
# 2.4 数值转换
有 3 个函数可以将非数值转换为数值:Number()、parseInt() 和 parseFloat()。Number() 是转型函数,可用于任何数据类型。后两个函数主要用于将字符串转换为数值。
# 2.4.1 Number()
Number() 函数基于如下规则执行转换。
- 布尔值,true 转换为 1,false 转换为 0。
- 数值,直接返回。
- null,返回 0。
- undefined,返回 NaN。
- 字符串,应用以下规则。
- 如果字符串包含数值字符,包括数值字符前面带加、减号的情况,则转换为一个十进制数值。因此,Number("1")返回 1,Number("123")返回 123,Number("011")返回 11(忽略前面的零)。
- 如果字符串包含有效的浮点值格式如"1.1",则会转换为相应的浮点值(同样,忽略前面的零)。
- 如果字符串包含有效的十六进制格式如"0xf",则会转换为与该十六进制值对应的十进制整数值。
- 如果是空字符串(不包含字符),则返回 0。
- 如果字符串包含除上述情况之外的其他字符,则返回 NaN。
- 对象,调用 valueOf() 方法,并按照上述规则转换返回的值。如果转换结果是 NaN,则调用 toString() 方法,再按照转换字符串的规则转换。
示例:
let num1 = Number("Hello world!"); // NaN
let num2 = Number(""); // 0
let num3 = Number("000011"); // 11
let num4 = Number(true); // 1
2
3
4
# 2.4.2 parseInt()
parseInt() 函数更专注于字符串是否包含数值模式。字符串最前面的空格会被忽略,从第一个非空格字符开始转换。如果第一个字符不是数值字符、加号或减号,parseInt() 立即返回 NaN。这意味着空字符串也会返回 NaN(这一点跟 Number() 不一样,它返回 0)。如果第一个字符是数值字符、加号或减号,则继续依次检测每个字符,直到字符串末尾,或碰到非数值字符。比如,"1234blue"会被转换为 1234,因为"blue"会被完全忽略。类似地,"22.5"会被转换为 22,因为小数点不是有效的整数字符。
下面几个转换示例有助于理解上述规则:
let num1 = parseInt("1234blue"); // 1234
let num2 = parseInt(""); // NaN
let num3 = parseInt("0xA"); // 10,解释为十六进制整数
let num4 = parseInt(22.5); // 22
let num5 = parseInt("70"); // 70,解释为十进制值
let num6 = parseInt("0xf"); // 15,解释为十六进制整数
2
3
4
5
6
通过第二个参数,可以极大扩展转换后获得的结果类型。比如:
let num1 = parseInt("10", 2); // 2,按二进制解析
let num2 = parseInt("10", 8); // 8,按八进制解析
let num3 = parseInt("10", 10); // 10,按十进制解析
let num4 = parseInt("10", 16); // 16,按十六进制解析
2
3
4
# 2.4.3 parseFloat()
parseFloat() 函数的工作方式跟 parseInt() 函数类似,都是从位置 0 开始检测每个字符。同样,它也是解析到字符串末尾或者解析到一个无效的浮点数值字符为止。这意味着第一次出现的小数点是有效的,但第二次出现的小数点就无效了,此时字符串的剩余字符都会被忽略。因此,"22.34.5"将转换成 22.34。
parseFloat() 函数的另一个不同之处在于,它始终忽略字符串开头的零。这个函数能识别前面讨论的所有浮点格式,以及十进制格式(开头的零始终被忽略)。十六进制数值始终会返回 0。因为 parseFloat() 只解析十进制值,因此不能指定底数。最后,如果字符串表示整数(没有小数点或者小数点后面只有一个零),则 parseFloat() 返回整数。
下面是几个示例:
let num1 = parseFloat("1234blue"); // 1234,按整数解析
let num2 = parseFloat("0xA"); // 0
let num3 = parseFloat("22.5"); // 22.5
let num4 = parseFloat("22.34.5"); // 22.34
let num5 = parseFloat("0908.5"); // 908.5
let num6 = parseFloat("3.125e7"); // 31250000
2
3
4
5
6
# 3、BigInt 任意大整数
BigInt 可以表示任意大的整数。其语法如下:
BigInt(value);
其中 value 是创建对象的数值。可以是字符串或者整数。
在 JavaScript 中,Number 基本类型可以精确表示的最大整数是2^53。因此早期会有这样的问题:
let max = Number.MAX_SAFE_INTEGER; // 最大安全整数
let max1 = max + 1
let max2 = max + 2
max1 === max2 // true
2
3
4
5
6
有了 BigInt 之后,这个问题就不复存在了:
let max = BigInt(Number.MAX_SAFE_INTEGER);
let max1 = max + 1n
let max2 = max + 2n
max1 === max2 // false
2
3
4
5
6
可以通过typeof操作符来判断变量是否为BigInt类型:
typeof 1n === 'bigint'; // true
typeof BigInt('1') === 'bigint'; // true
2
还可以通过Object.prototype.toString方法来判断变量是否为BigInt类型:
Object.prototype.toString.call(10n) === '[object BigInt]'; // true
# 4、Boolean 布尔值
Boolean 类型有两个字面值:true 和 false。
赋值例子:
let found = true;
let lost = false;
2
注意,布尔值字面量 true 和 false 是区分大小写的,因此 True 和 False(及其他大小混写形式)是有效的标识符,但不是布尔值
调用特定的 Boolean()转型函数,可以转换为布尔值,下表总结了不同类型与布尔值之间的转换规则。
数据类型 | 转换为 true 的值 | 转换为 false 的值 |
---|---|---|
Boolean | true | false |
String | 非空字符串 | ""(空字符串) |
Number | 非零数值(包括无穷值) | 0、NaN(参见后面的相关内容) |
Object | 任意对象 | null |
Undefined | N/A(不存在) | undefined |
示例:
let test = Boolean('test');
console.log(test); // true
2
# 4.1 虚值
falsy 值 (虚值) 是在 Boolean 上下文中认定为 false 的值。
JavaScript 在需要用到布尔类型值的上下文中使用强制类型转换(Type Conversion )将值转换为布尔值,例如条件语句和循环语句。
在 JavaScript 中只有 8 个 falsy 值。
这意味着当 JavaScript 期望一个布尔值,并被给与下面值中的一个时,它总是会被当做 false。
值 | 说明 |
---|---|
false | false 关键字 |
0 | 数值 负 zero |
-0 | false 关键字 |
0n | 当 BigInt 作为布尔值使用时, 遵从其作为数值的规则. 0n 是 falsy 值 |
"" '' `` | 这是一个空字符串 (字符串的长度为零). JavaScript 中的字符串可用双引号 "", 单引号 '', 或 模板字面量 `` 定义。 |
null | null - 缺少值 |
undefined | undefined - 原始值 |
NaN | NaN - 非数值 |
JavaScript 中 falsy 值的例子 (在布尔值上下文中被转换为 false,从而绕过了 if 代码块):
if (false)
if (null)
if (undefined)
if (0)
if (0n)
if (NaN)
if ('')
if ("")
if (``)
if (document.all)
2
3
4
5
6
7
8
9
10
# 4.2 逻辑与操作符 &&
如果第一个对象是 falsy 值,则返回那个对象:
let pet = false && "dog";
// false
2
document.all
在过去被用于浏览器检测,是 HTML 规范在此定义了故意与 ECMAScript 标准相违背的(document.all
虽然是一个对象,但其转换为 boolean 类型是 false),以保持与历史代码的兼容性(if (document.all) { // Internet Explorer code here }
或使用document.all
而不先检查它的存在:document.all.foo
)。\
falsy 有时会写作 falsey,虽然在英语中,将一个单词转换成形容词时,通常会去掉末尾的字母 e,加上后缀 y。(noise => noisy, ice => icy, shine => shiny)
# 5、Null 空值
Null 类型只有一个值,即特殊值 null。逻辑上讲,null 值表示一个空对象指针,这也是给 typeof 传一个 null 会返回"object"的原因:
console.log(typeof null); // "object"
在定义将来要保存对象值的变量时,建议使用 null 来初始化,不要使用其他值。这样,只要检查这个变量的值是不是 null 就可以知道这个变量是否在后来被重新赋予了一个对象的引用,比如:
if (car != null) {
// car 是一个对象的引用
}
2
3
undefined 值是由 null 值派生而来的,因此 ECMA-262 将它们定义为表面上相等,如下面的例子所示:
console.log(null == undefined); // true
# 6、Undefined 未定义
Undefined 类型只有一个值,就是特殊值 undefined。当使用 var 或 let 声明了变量但没有初始化时,就相当于给变量赋予了 undefined 值:
let message;
console.log(message == undefined); // true
2
注意:一般来说,永远不用显式地给某个变量设置 undefined 值。字面值 undefined 主要用于比较,而且在 ECMA-262 第 3 版之前是不存在的。增加这个特殊值的目的就是为了正式明确空对象指针(null)和未初始化变量的区别。
# 7、Symbol 符号
Symbol(符号)是 ECMAScript 6 新增的数据类型。符号是原始值,且符号实例是唯一、不可变的。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
详细 Symbol
# 8、总结
String 字符串
- 使用 '' "" `` 符号标识
- 字符字面量:
\n 换行
,\t 制表
,\b 退格
,\r 回车
,\f 换页
,\\ 反斜杠
,\' 单引号
,\" 双引号
,\xnn 十六进制编码 nn 表示的字符
,\unnn 十六进制编码 nnnn 表示的 Unicode 字符
- 字符串是不可变的
String.raw`\u00A9`;
标签函数的使用toString()
方法可用于数值、布尔值、对象和字符串值的转换为字符串
Number 数值
- 使用 IEEE 754 格式表示整数和浮点值
- 浮点值
0.1+ 0.2 != 0.3
- 换成别的数字:
(0.1 * 10 + 0.2 * 10) / 10 === 0.3
- 保留小数位数:
parseFloat((0.1 + 0.2).toFixed(10)) === 0.3
- 换成别的数字:
- Number.MIN_VALUE 最小值,Number.MAX_VALUE 最大值,超过最小值和最大值使用Infinity(无穷)和-Infinity(负无穷大)来表示
isFinite()
函数判断数值是否在最小值和最大值之间NaN
意思是“不是数值”(Not a Number)用于表示本来要返回数值的操作失败了(而不是抛出错误)- 0除以任意数都返回 NaN,
- 非零数除以零返回 Infinity 或-Infinity
- NaN != NaN
isNaN()
函数判断参数是否"不是数值"
- 数值转换:
Number()
、parseInt()
和parseFloat()
Number()
支持布尔值、数值、null、undefined、字符串、对象等类型的转换parseInt()
更专注于字符串,返回整数;接收第二个参数,支持二进制、八进制、十进制、十六进制parseFloat()
支持浮点型字符串转换,只支持十进制转换
BigInt 任意大整数
- 支持超过
Number.MAX_SAFE_INTEGER
最大整数(2^53) - 在数值后面加 n 表示,例如:
2n
- 支持超过
Boolean 布尔值
- 只有两个字面量:true 和 false
- 布尔值字面量区分大小写,True 和 False 是有效标识符
Boolean()
转型函数- 布尔值,可以直接转换
- String,非空字符串为 true
- Number,非 0 数值为 true
- Object,任意对象为 true,null 为 false
- Undefined,N/A 为 true,undefined 为 false
- 虚值(被认定为false):
false
、0
、-0
、0n
、"空字符串"
、null
、undefined
、NaN
Null 空值
- null 值表示一个空对象指针
- typeof null 结果为 object
- null == undefined
Undefined 未定义
当使用 var 或 let 声明了变量但没有初始化时,就相当于给变量赋予了 undefined 值
- Symbol 符号
符号是原始值,且符号实例是唯一、不可变的。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。