目录
- JS 8 种数据类型
- Number 之 0.1+0.2 !== 0.3
- BigInt 之突破最大的限制
- Symbol(表示独一无二的值)
- 数据类型判断
一 JS 8 种数据类型
Javascript 中的数据类型包括原始类型和引用类型。(以下只有 Object 是引用类型。)
- Number
- String
- Boolean
- Null (空对象指针)
- undefined (未定义的变量)
- Symbol(表示独一无二的值)
- BigInt
- Object
1.1 Null 和 Undefined 的区别和应用
Null 表示没有对象,该处不应该有值。
比如:原型链的终点,如下。
Object.getPrototypeOf(Object.prototype)
Undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
- 变量被声明了,但没有赋值时,就等于
undefined。 - 调用函数时,应该提供的参数没有提供,该参数等于
undefined。 - 对象没有赋值的属性,该属性的值为
undefined。 - 函数没有返回值时,默认返回
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 时,返回其右侧操作数,否则返回左侧操作数
二 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.000110011001100110011(0011无限循环)……
JavaScript是以64位双精度浮点数存储所有Number类型值,按照IEEE754规范,0.1 的二进制数只保留52 位有效数字所以说,精度丢失并不是语言的问题,而是浮点数存储本身固有的缺陷。
这样在进制之间的转换中精度已经损失。运算的时候如下
0.00011001100110011001100110011001100110011001100110011010
+0.00110011001100110011001100110011001100110011001100110100
------------------------------------------------------------
=0.01001100110011001100110011001100110011001100110011001110
所以导致了最后的计算结果中
0.1 + 0.2 !== 0.3;// true
如何解决(共三种方法)
- 将数字转成整数
NPM上有许多支持JavaScript和Node.js的数学库,比如math.js,decimal.js,D.js等等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)
应用场景
- 定义一组常量,保证这组常量都是不相等的。消除魔法字符串
- 对象中保证不同的属性名
五 数据类型判断
判断一个值属于那种数据类型共有三种方式,分别为
typeof、instanceof和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]'
六 为什么做「 JS 基础回顾 」
写作是一个回顾的过程,尝试写这个系列也主要是为了巩固 JavaScript 基础,并尝试理解其中的一些知识点,以便能灵活运用。如果有错误或者不严谨的地方,请务必给予指正,十分感谢! 整个系列会持续更新,不会完结。
参考
总结
精度丢失并不是语言的问题,而是浮点数存储本身固有的缺陷。- 判断一个值属于那种数据类型共有三种方式,分别为
typeof、instanceof和Object.prototype.toString()