JavaScript 数据类型

ECMAScript 有 6 种简单数据类型(也称为原始类型):UndefinedNullBooleanNumberStringSymbol。还有一种复杂数据类型叫 Object(对 象)。Object 是一种无序名值对的集合。

UndefinedNull

Undefined 类型只有一个值 undefined,当使用 letvar 声明变量单并没有初始化时,就相当于给变量赋予了 undefined 值。

一般来说不建议显式的给变量赋值 undefined,字面值 undefined 主要是用来比较。

1
2
3
4
5
let v1;
var v2;
console.log(v1); // undefined
console.log(v2); // undefined
console.log(v1 === v2); // true

增加这个特殊值的目的就是为了正式明确空对象指针 null 和未初始化变量的区别。

undefined 值是由 null 值派生而来的,因此 ECMA-262 将它们定义为表面上相等,如下所示:

1
2
console.log(null === undefined); // false
console.log(null == undefined); // true

Null 类型同样只有一个值,即特殊值 null。逻辑上讲,null 值表示一个空对象指针,这也是给 typeof 传一个 null 会返回 “object” 的原因。

1
2
let v3 = null;
console.log(typeof v3); // "object"

在定义将来要保存对象值的变量时,建议使用 null 来初始化,不要使用其他值。这样,只要检查这个变量的值是不是 null 就可以知道这个变量是否在后来被重新赋予了一个对象的引用。

undefinednull 都是假值,如果只是为了检测假值,可以方便的检测它们;如果是明确的想要检测 undefinednull,则需要显式的对其进行判断。

1
2
3
4
5
6
let v4;
let o1 = null;
console.log(!v4); // true
console.log(v4 === undefined); // true
console.log(!o1); // true
console.log(o1 === null); // true

Boolean

Boolean 类型是使用非常频繁的数据类型,它有两个值 truefalse (布尔值字面量是区分大小写的)。

这两个布尔值并不等同于数值:

1
2
3
4
let t1 = true;
let f1 = false;
console.log(t1 === 1); // false
console.log(f1 === 0); // false

虽然布尔值只有两个,但所有其他 ECMAScript 类型的值都有相应布尔值的等价形式。要将一个其他类型的值转换为布尔值,可以调用特定的 Boolean() 转型函数。

1
2
3
4
5
6
7
8
9
10
11
console.log(Boolean(true)); // true
console.log(Boolean(false)); // false
console.log(Boolean('true')); // true
console.log(Boolean('false')); // true
console.log(Boolean(0)); // false
console.log(Boolean(-0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(1)); // true
console.log(Boolean(-1)); // true
console.log(Boolean('')); // false
console.log(Boolean(' ')); // true

Number

Number 类型使用 IEEE 754 格式表示整 数和浮点值(在某些语言中也叫双精度值)。不同的数值类型相应地也有不同的数值字面量格式。

image-20201223142823585

整数可以用八进制、十进制和十六进制字面量表示,但是使用八进制和十六进制格式创建的数值在所有数学操作中都被视为十进制数值。

1
2
3
4
5
6
let octalNum = 077;
let hexNum = 0xff;
console.log(octalNum); // 63
console.log(hexNum); // 255
let sum = octalNum + hexNum;
console.log(sum); // 318

浮点值

要定义浮点值,数值中必须包含小数点,而且小数点后面必须至少有一个数字。虽然小数点前面不是必须有整数,但推荐加上。

1
2
let float1 = 1.01;
let float2 = .01;

因为存储浮点值使用的内存空间是存储整数值的两倍,所以 ECMAScript 总是想方设法把值转换为 整数。在小数点后面没有数字的情况下,数值就会变成整数。类似地,如果数值本身就是整数,只是小 数点后面跟着 0(如 1.0),那它也会被转换为整数。

对于非常大或非常小的数值,浮点值可以用科学记数法来表示。科学记数法用于表示一个应该乘以 10 的给定次幂的数值。ECMAScript 中科学记数法的格式要求是一个数值(整数或浮点数)后跟一个大 写或小写的字母 e,再加上一个要乘的 10 的多少次幂

1
2
3
4
let float3 = 2.23e9;
console.log(float3); //2230000000
let float4 = 1.01e-5;
console.log(float4); // 0.0000101

浮点值的精确度最高可达 17 位小数,但在算术计算中远不如整数精确。例如,0.1 加 0.2 得到的不 是 0.3,而是 0.300 000 000 000 000 04。由于这种微小的舍入错误,导致很难测试特定的浮点值。

1
2
3
let float5 = 0.1;
let float6 = 0.2;
console.log(float5 + float6); // 0.30000000000000004

之所以存在这种舍入错误,是因为使用了 IEEE 754 数值,这种错误并非 ECMAScript 所独有。其他使用相同格式的语言也有这个问题。

因此永远不要测试某个特定的浮点值。

使用最小精度值来比较浮点数:

1
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);

值的范围

ECMAScript 可以表示的最小 数值保存在 Number.MIN_VALUE 中,这个值在多数浏览器中是 5e-324;可以表示的最大数值保存在 Number.MAX_VALUE 中,这个值在多数浏览器中是 1.7976931348623157e+308。如果某个计算得到的数值结果超出了 JavaScript 可以表示的范围,那么这个数值会被自动转换为一个特殊的 Infinity(无 穷)值。任何无法表示的负数以 -Infinity(负无穷大)表示,任何无法表示的正数以 Infinity(正 无穷大)表示。

1
2
console.log(Number.MIN_VALUE); // 5e-234
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308

如果计算返回正 Infinity 或负 Infinity , 则该值将不能再进一步用于任何计算。 这是因为 Infinity 没有可用于计算的数值表示形式。要确定一个值是不是有限大(即介于 JavaScript 能表示的最小值和最大值之间),可以使用 isFinite() 函数。

1
2
3
4
let num1 = 6e-325;
let num2 = 1.8e308;
console.log(Number.isFinite(num1)); // false
console.log(Number.isFinite(num2)); // false

Number.NEGATIVE_INFINITYNumber.POSITIVE_INFINITY 也可以获取正、负 Infinity。没错,这两个属性包含的值分别就是 -InfinityInfinity

NaN

有一个特殊的数值叫 NaN,意思是 “不是数值”(Not a Number),用于表示本来要返回数值的操作 失败了(而不是抛出错误)。比如,用 0 除任意数值在其他语言中通常都会导致错误,从而中止代码执 行。但在 ECMAScript 中,0、+0 或-0 相除会返回 NaN

1
2
3
4
console.log(Number.parseFloat('f1.f')); // NaN
console.log(1/0); // Infinity
console.log(0/1); // 0
console.log(0/0); // NaN

NaN 有几个独特的属性。首先,任何涉及 NaN 的操作始终返回 NaN(如 NaN/10),在连续多步计算 时这可能是个问题。其次,NaN 不等于包括 NaN 在内的任何值。

1
2
console.log(0/0 === NaN); // false
console.log(NaN === NaN); // false

要判断一个值是不是 NaN, 可以使用 isNaN() 函数。

1
2
console.log(Number.isNaN(0/0)); // true
console.log(Number.isNaN(true)); // false

数值转换

JavaScript 中提供了 Number()parseInt()parseFloat() 三个方法用来将非数值转换为数值。

Number
1
2
3
4
5
6
7
8
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(1000)); // 1000
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
console.log(Number('12')); // 12
console.log(Number(' 12')); // 12
console.log(Number('12-')); // NaN
parseInt()

parseInt() 函数更专注于字符串是否包含数值模式。字符串最前面的空格会被忽略,从第一个非空格字符开始转换。如果第一个字符不是数值字符、加号或减号,parseInt() 立即 返回 NaN。这意味着空字符串也会返回 NaN(这一点跟 Number() 不一样,它返回 0)。如果第一个字符 是数值字符、加号或减号,则继续依次检测每个字符,直到字符串末尾,或碰到非数值字符。

1
2
3
4
5
6
console.log(parseInt(100)); // 100
console.log(parseInt('1000')); // 1000
console.log(parseInt('1000lll')); // 1000
console.log(parseInt(' 1000')); // 1000
console.log(parseInt('001000')); // 1000
console.log(parseInt('a 1000')); // NaN

parseInt() 也接收第二个参数,用于指定底数(进制数)。

1
2
console.log(parseInt('077', 8)); // 63
console.log(parseInt('0xff', 16)); // 255

不传底数参数相当于让 parseInt() 自己决定如何解析,所以为避免解析出错,建议始终传给 它第二个参数。

parseFloat()

parseFloat() 函数的工作方式跟 parseInt() 函数类似,都是从位置 0 开始检测每个字符。同样, 它也是解析到字符串末尾或者解析到一个无效的浮点数值字符为止。这意味着第一次出现的小数点是有效的,但第二次出现的小数点就无效了,此时字符串的剩余字符都会被忽略。

1
2
3
4
5
6
7
console.log(parseFloat('-1.01')); // -1.01
console.log(parseFloat('1.01')); // 1.01
console.log(parseFloat('1.01.01')); // 1.01
console.log(parseFloat(' 1.01')); // 1.01
console.log(parseFloat('a1.01')); // NaN
console.log(parseFloat('1.01a')); // 1.01
console.log(parseFloat('00001.01a')); // 1.01

String

String(字符串)数据类型表示零或多个 16 位 Unicode 字符序列。

image-20201223160958920

ECMAScript 中的字符串是不可变的(immutable),意思是一旦创建,它们的值就不能变了。要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量。

把值转换为字符串

使用 toString() 方法

nullundefined 没有 toString() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
let val1 = 12;
let val2= '12';
let val3 = [1,2];
let val4 = new Date();
let val5 = {};

// 12 12 1,2 Fri Dec 25 2020 13:48:14 GMT+0800 (China Standard Time) [object Object]
console.log(val1.toString(), val2.toString(), val3.toString(), val4.toString(), val5.toString());

null.toString(); // Uncaught TypeError: Cannot read property 'toString' of undefined

undefined.toString(); // Uncaught TypeError: Cannot read property 'toString' of null

在对数字类型值调用 toString() 方法时,可传递一个参数指定以什么底数输出数值的字符串表示。

1
2
3
4
5
6
let numVal = 123;

console.log(numVal.toString(2)); // 1111011
console.log(numVal.toString(8)); // 173
console.log(numVal.toString(10)); // 123
console.log(numVal.toString(16)); // 7b
使用 String()

在使用 String() 将值转换为字符串时,如果值有 toString() 方法,则直接调用 toString() 方法并返回结果。对于没有 toString() 方法的 nullundefined ,则会分别返回 “null” 和 “undefiend”。

1
2
console.log(String(null));
console.log(String(undefined));

Symbol

Symbol(符号)是 ECMAScript 6 新增的数据类型。符号是原始值,且符号实例是唯一不可变的。 符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。

尽管听起来跟私有属性有点类似,但符号并不是为了提供私有属性的行为才增加的。相反,符号就是用来创建唯一记号,进而用作非字符串形式的对象属性。

1
2
3
4
let s1 = Symbol();
let s2 = Symbol('s2');
console.log(s1);
console.log(s2);

Object

ECMAScript 中的对象其实就是一组数据和功能的集合。对象通过 new 操作符后跟对象类型的名称 来创建。

作者

Y2hlbmdsZWk=

发布于

2019-06-25

更新于

2021-09-01

许可协议