likes
comments
collection
share

每日五道前端面试题--day2

作者站长头像
站长
· 阅读数 10

第二天要刷的面试题如下:

  1. 为什么在js中0.1+0.2!==0.3?如何使其相等?
  2. 如何获取安全的undefined的值?
  3. typeof NaN的结果是什么?
  4. isNaN和Number.isNaN的区别是什么?
  5. 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的正确性;
  1. 对于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报错。

  2. 对于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类型的时候会按照一下流程:

    1. 查看object上是否实现了valueof方法,如果有则跳到4,如果没有实现则;
    1. 查看object上是否实现了toSting方法,如果有则跳到5,如果没有实现则;
    1. 返回not a number, 但不是NaN;
Object.is({}, NaN) // false
Number.isNaN({}) // false
isNaN({}) // true
    1. 假如valueof方法的返回值为y,如果typeof y为"object",则直接报错;如果不为"object",则返回Number(y);
    1. 假如toSting方法的返回值为z,如果typeof z为"object",则直接报错;如果不为"object",则返回Number(z);