「 JS 基础回顾 」- 数据类型

199 阅读4分钟

目录

  1. JS 8 种数据类型
  2. Number 之 0.1+0.2 !== 0.3
  3. BigInt 之突破最大的限制
  4. Symbol(表示独一无二的值)
  5. 数据类型判断

一 JS 8 种数据类型

Javascript 中的数据类型包括原始类型引用类型。(以下只有 Object 是引用类型。)

  1. Number
  2. String
  3. Boolean
  4. Null (空对象指针)
  5. undefined (未定义的变量)
  6. Symbol(表示独一无二的值)
  7. BigInt
  8. Object

1.1 NullUndefined 的区别和应用

Null 表示没有对象,该处不应该有值。

比如:原型链的终点,如下。

Object.getPrototypeOf(Object.prototype)

Undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:

  1. 变量被声明了,但没有赋值时,就等于 undefined
  2. 调用函数时,应该提供的参数没有提供,该参数等于undefined
  3. 对象没有赋值的属性,该属性的值为 undefined
  4. 函数没有返回值时,默认返回 undefined

1.2 判空应该注意什么?

javaScript 五种空值和假值,分别为 undefined,null,false,"",0,NAN

这有时候很容易导致一些问题,比如,以下通过 || 判断是上面 5 种空值和假值,只要是这 5 种值,都会输出 1。除非我们用 严格等于来单独判断 undefined,null。下方我们有更好的方法用空值合并操作符

var b;
b == null; 
b || 1;
// 输出 1

我们可以通过 ?? 来只判断 undefined,null 空值合并操作符(??)是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数

image.png

二 Number 之 0.1+0.2 !== 0.3

JS表现如下:

0.1 + 0.2
// 0.30000000000000004

原因:

我们在对浮点数进行运算的过程中,需要将十进制转换成二进制

通过 API 转换,我们看到 0.1 0.2的二进制都为 0 ,

(2).toString(2) // '10'
parseInt(2).toString(2) // '10'
parseInt(1).toString(2) // '1'

parseInt(0.2).toString(2); // '0'
parseInt(0.1).toString(2); // '0'

实际上0.1是:

0.0001100110011001100110011无限循环)……

JavaScript 是以 64 位双精度浮点数存储所有 Number 类型值,按照 IEEE754 规范,0.1 的二进制数只保留 52 位有效数字 所以说,精度丢失并不是语言的问题,而是浮点数存储本身固有的缺陷

这样在进制之间的转换中精度已经损失。运算的时候如下

0.00011001100110011001100110011001100110011001100110011010
+0.00110011001100110011001100110011001100110011001100110100
------------------------------------------------------------
=0.01001100110011001100110011001100110011001100110011001110

所以导致了最后的计算结果中 0.1 + 0.2 !== 0.3;// true

如何解决(共三种方法)

  1. 将数字转成整数
  2. NPM 上有许多支持 JavaScript 和 Node.js 的数学库,比如 math.jsdecimal.js,D.js 等等
  3. ES6 在 Number 对象上新增了一个极小的常量——Number.EPSILON
Number.EPSILON
// 2.220446049250313e-16
Number.EPSILON.toFixed(20) 
// "0.00000000000000022204"

引入一个这么小的量,目的在于为浮点数计算设置一个误差范围,如果误差能够小于 Number.EPSILON,我们就可以认为结果是可靠的

function withinErrorMargin (left, right) {
    return Math.abs(left - right) < Number.EPSILON
}
withinErrorMargin(0.1+0.2, 0.3)

三 BigInt 之突破最大的限制

JavaScript 的 Number 类型为 双精度IEEE 754 64位浮点类型。 在 JavaScript 中最大的值为 2^53

Math.pow(2,53)
// 9007199254740992
Math.pow(2,53) +1
// 9007199254740992

BigInt 可以表示任意大的整数。要创建一个 BigInt ,我们只需要在任意整型的字面量上加上一个 n 后缀即可。例如,把123 写成 123n。这个全局的 BigInt(number) 可以用来将一个 Number 转换为一个 BigInt,言外之意就是说,BigInt(123) === 123n

四 Symbol(表示独一无二的值)

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值 传入参数为标识串。

var b =  Symbol('bbb');
// Symbol(bbb)

应用场景

  • 定义一组常量,保证这组常量都是不相等的。消除魔法字符串
  • 对象中保证不同的属性名

五 数据类型判断

判断一个值属于那种数据类型共有三种方式,分别为 typeofinstanceof 和 Object.prototype.toString()

typeof

一般通过 typeof 操作符来判断一个值属于哪种基本类型。

typeof 'seymoe'    // 'string'
typeof true        // 'boolean'
typeof 10          // 'number'
typeof Symbol()    // 'symbol'
typeof null        // 'object' 无法判定是否为 null
typeof undefined   // 'undefined'
typeof {} // 'object' 
typeof [] // 'object' 
typeof(() => {}) // 'function'

instanceof

通过 instanceof 操作符也可以对对象类型进行判定,其原理就是测试构造函数的 prototype 是否出现在被检测对象的原型链上

[] instanceof Array            // true
({}) instanceof Object         // true
(()=>{}) instanceof Function   // true

Object.prototype.toString()

由于用户可以改写(见下方截图),所以我们用 call的方式调用 Object.prototype.toString。

Object.prototype.toString.call({})              // '[object Object]'
Object.prototype.toString.call([])              // '[object Array]'
Object.prototype.toString.call(() => {})        // '[object Function]'
Object.prototype.toString.call('seymoe')        // '[object String]'
Object.prototype.toString.call(1)               // '[object Number]'
Object.prototype.toString.call(true)            // '[object Boolean]'
Object.prototype.toString.call(Symbol())        // '[object Symbol]'
Object.prototype.toString.call(null)            // '[object Null]'
Object.prototype.toString.call(undefined)       // '[object Undefined]'

Object.prototype.toString.call(new Date())      // '[object Date]'
Object.prototype.toString.call(Math)            // '[object Math]'
Object.prototype.toString.call(new Set())       // '[object Set]'
Object.prototype.toString.call(new WeakSet())   // '[object WeakSet]'
Object.prototype.toString.call(new Map())       // '[object Map]'
Object.prototype.toString.call(new WeakMap())   // '[object WeakMap]'

image.png

六 为什么做「 JS 基础回顾 」

写作是一个回顾的过程,尝试写这个系列也主要是为了巩固 JavaScript 基础,并尝试理解其中的一些知识点,以便能灵活运用。如果有错误或者不严谨的地方,请务必给予指正,十分感谢! 整个系列会持续更新,不会完结。

参考

总结

  1. 精度丢失并不是语言的问题,而是浮点数存储本身固有的缺陷
  2. 判断一个值属于那种数据类型共有三种方式,分别为 typeofinstanceof 和 Object.prototype.toString()