Javascript数据类型
JavaScript 有 8 种类型的值呢,如果再归归类,我们还可以把它们分为两大类,分别是 原始类型(Primitive Type)和 对象类型(Object Type)。其中,原始数据类型包含了数字
、布尔
、字符串
、BigInt
、null
、undefined
,以及后来新增的 symbol
,这个数据类型的值都是不可变的(immutable)。对象数据类型则包含我们经常说的对象,对象的值是可变的(mutable)。它是一个大类,如果再细分,它又包含了我们常用的 数组(array)
、函数(function)
、Date
、RegExp
,以及后来新增的 Map
和 Set
。没错,我们经常用的数组、函数作为值都属于对象数据类型。
平常都比较注意引用类型带来的问题,但是比较忽略原始类型带来的痛楚,比如社区比较火爆的 0.1 + 0.2 === 03 不成立问题,这是因为精度丢失导致的。
JavaScript 的数字有两种类型分别是 整数 和 浮点数,而这个问题是浮点数之间的运算,浮点数可以很大也可以很小,位数越多占用的存储空间就越多,解决办法就是使用 科学计数法。JavaScript 所采用的 IEEE 754 是 二进制 浮点数算术标准。这个标准里规定了 4 种浮点数算术方式:单精确度、双精确度、延伸单精确度与延伸双精确度。JavaScript 在这里选择的又是 双精确度(64 位)这种方式,通常也叫 double 或者 float64 类型。把十进制转化为二进制的算法是用十进制的小数乘以 2 直到没有了小数为止,所以十进制下的有些小数无法被精确地表示成二进制小数。而既然这里的浮点数是二进制,因此小数就会存在 精度丢失 的问题。
而且当我们使用加减法的时候,由于需要先对齐(也就是把指数对齐,过程中产生移位),再计算,所以这个精度会进一步丢失。并且根据 JavaScript 引擎实际返回的小数点后的位数,可能会出现第三次丢失。这样下来,最后的结果就和实际相加减的数有偏离。
所以一般开发的时候都是把小数先放大倍数,做完运算后再缩小。
再比如虽然布尔类型的数据只有 true 和 false 两种,但是在 JavaScript 中除了 false 以外,undefined、null、0、NAN 和 ” 都是假值。
再比如 null 实际是一个空的对象指针
….
接下来,来好好理一理开发的时候应该怎么去判断 JavaScript 的各种数据类型
类型判断
typeof
typeof 是 一元操作符,放在单个操作数的前面,操作数可以是任意类型。返回值为表示操作数类型的一个字符串。
用 typeof
检测 JavaScript 中所有的数据类型会得到如下的结果
操作 | 结果 |
---|---|
typeof ‘string’ | ‘string’ |
typeof 1 | ‘number’ |
typeof true | ‘boolean’ |
typeof undefined | ‘undefined’ |
typeof Symbol() | ‘symbol’ |
typeof null | ‘object’ |
typeof {} | ‘object’ |
typeof function test() {} | ‘function’ |
typeof [] | ‘object’ |
typeof new Map() | ‘object’ |
typeof new Set() | ‘object’ |
typeof new Date() | ‘object’ |
typeof new Error() | ‘object’ |
可以看到,除开 typeof null === 'object'
是个 bug 不考虑以外,只有函数类型的对象能检测出来是个函数,也没有办法具体检测是个什么类型的函数,很多种正常类型的对象是没有办法检测出来具体的对象类型,咋办呢?Object.prototype.toString 是神器
Object.prototype.toString
早期写代码经常会搜类型判断,最常见的就是 Object.prototype.toString
,来看看对所有类型进行 toString 后是什么结果,ES5 规范 其实也写的很清楚了,我再翻译一下:
- 如果 this 值是 undefined,就返回 [object Undefined]
- 如果 this 的值是 null,就返回 [object Null]
- 让 O 成为 ToObject(this) 的结果
- 让 class 成为 O 的内部属性 [[Class]] 的值
- 最后返回由 “[object **” 和 class 和 “]**” 三个部分组成的字符串
通过规范,我们至少知道了调用 Object.prototype.toString 会返回一个由 “[object **” 和 **class 和 “]” 组成的字符串,而 class 是要判断的对象的内部属性。
用 Object.prototype.toString(表格中简写为toString)
检测 JavaScript 中大部分常见的数据类型会得到如下的结果
操作 | 结果 |
---|---|
toString ‘string’ | [object String] |
toString 1 | [object Number] |
toString true | [object Boolean] |
toString undefined | [object Undefined] |
toString null | [object Null] |
toString {} | [object Object] |
toString [] | [object Array] |
toString new Date() | [object Date] |
toString new Error() | [object Error] |
toString /a/g | [object RegExp] |
toString function test() {} | [object Function] |
toString Math | [object Math] |
toString JSON | [object JSON] |
Object.prototype.toString.call(new Map()) | [object Map] |
Object.prototype.toString.call(new Set()) | [object Set] |
Object.prototype.toString.call(Symbol()) | [object Symbol] |
function test() {console.log(Object.prototype.toString(arguments))} | [object Arguments] |
…… | …… |