以下题目来自掘金等其它博客,但是问题的答案都是根据笔者自己的理解做出的。如果你最近想要换工作或者巩固一下自己的前端知识基础,不妨和我一起参与到每日刷题的过程中来,如何?
第二天要刷的面试题如下:
- 为什么在js中0.1+0.2!==0.3?如何使其相等?
- 如何获取安全的undefined的值?
- typeof NaN的结果是什么?
- isNaN和Number.isNaN的区别是什么?
- js中,将其他类型值隐式转变成number类型的机制是什么?
下面是我自己的理解:
1. 为什么在js中0.1+0.2!==0.3?如何使其相等?
- js中存储数据遵循IEEE754双精度浮点数标准。这个规定要求使用64bit存储一个双精度的浮点数,其中1bit表示符号位,11bit表示指数位,剩下的52位表示尾数,也就是说js中对于一个浮点数的存储是有限位的;
- 0.1虽然在十进制中很好表示,但是在二进制中却是一个无限循环小数,因为不论2的几次方都不可能凑到10;所以使用
0.1.toString(2)
可以清楚的看到这个截断了的无限循环小数;同理0.2也是这样; - 所以两个无限小数相加并且被截断之后,其结果必然产生截断误差,所以0.1+0.2才不等于0.3;
- 为了避免这种情况,应该手动设置一个最小误差,比如1e-9:
function add (a, b) {
return parseFloat((a+b).toFixed(9));
}
// 验证
console.log(add(0.1,0.2)===0.3)
2. 如何获取安全的undefined的值?
在回答这个问题之前,先看一些事实:
- 如果在浏览器中运行
const undefined = 20;
则浏览器报错:Identifier 'undefined' has already been declared'; 而如果运行的是:const null = 20;
浏览器报错为:unexpected token 'null'; - 也就是说对于浏览器来说undefined只是一个普通的identifier而不是token;也就是说undefined是标识符而不是保留字!
- 这一点在node环境中表现的更加的透彻:
let undefined = 20;
console.log(undefined); // 20
- 所以undefined作为标识符其值是有被篡改的风险的。在实际中一般使用
void 0 或者 void(0)
表示undefined的含义,因为这个表达式的返回值恒为此。
3. typeof NaN的结果是什么?
先说结论,返回值为:'number'
注意这里的字符串和小写。
NaN有几个特性,一个是不和自身相等;第二个是在Object.is中又是相等的;第三个是表示的语义为:not a number
4. isNaN和Number.isNaN的区别是什么?
- 两者表示完全不同的语义,是完全不相同的两个方法!
- isNaN(x)是在判断
x is not a number
的正确性; - 而Number.isNaN(x)是在判断
x is NaN
的正确性;
-
对于isNaN(x)来说,只要x不是一个num就会返回true,反之返回false。(注意这里我用的是num,也就是一种独特的东西,和number类型不是一回事)
那么,isNaN对于x的判定规则是什么呢?其实非常简单,首先x如果值为NaN,则isNaN认为x不是一个num;其次,如果x不为NaN,但却是number类型,则isNaN认为x是一个num;最后,倘若x不是number类型的,isNaN会尝试将x转成number类型(这种转化不同于Number(x)的强制类型转化,是内部机制),而转化的结果有三种:①NaN,②报错,③其他;
如果是第一种则isNaN认为x不是num,如果是第三种,isNaN认为x是num。什么时候会出现情况②呢,如果x的类型是bigint或者symbol就会使isNaN报错。
-
对于Number.isNaN(x)来说,情况就简单的多了,只要x不是NaN就返回false,否则返回true.
这里补充js中的哪些计算会返回NaN来:
- NaN
- Number.NaN
- 'abc' - 1
- 0 / 0
- Math.aqrt(-1)
- Number({})
- Number('abc')
5. js中,将其他类型值隐式转变成number类型的机制是什么?
js中的数据类型有八种,接下来对着八种逐一进行分析:
- null: 隐式转换成0
- undefined: 隐式转换成NaN
- string: ①0 ②8,10,16进制对应数 ③NaN
- number: 原样返回
- boolean: true 1, false 0
- symbol: 报错
- bigint: 报错
- object: 内部机制
总结一下就是:对于null, undefined, string, boolean来说相当于显式调用Number()进行强转;对于bigint和symbol来说会报错(但是Number()对bigint不会报错,但对symbol仍然报错);对于object会触发内部机制。
那么内部机制是什么呢?object中有primitive机制和defaultValue机制,当将一个object隐式转成number类型的时候会按照一下流程:
-
- 查看object上是否实现了valueof方法,如果有则跳到4,如果没有实现则;
-
- 查看object上是否实现了toSting方法,如果有则跳到5,如果没有实现则;
-
- 返回not a number, 但不是NaN;
Object.is({}, NaN) // false
Number.isNaN({}) // false
isNaN({}) // true
-
- 假如valueof方法的返回值为y,如果typeof y为"object",则直接报错;如果不为"object",则返回Number(y);
-
- 假如toSting方法的返回值为z,如果typeof z为"object",则直接报错;如果不为"object",则返回Number(z);