Javascript数据类型

JavaScript 有 8 种类型的值呢,如果再归归类,我们还可以把它们分为两大类,分别是 原始类型(Primitive Type)和 对象类型(Object Type)。其中,原始数据类型包含了数字布尔字符串BigIntnullundefined,以及后来新增的 symbol,这个数据类型的值都是不可变的(immutable)。对象数据类型则包含我们经常说的对象,对象的值是可变的(mutable)。它是一个大类,如果再细分,它又包含了我们常用的 数组(array)函数(function)DateRegExp,以及后来新增的 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]
…… ……
(adsbygoogle = window.adsbygoogle || []).push({});