【0.1+0.2 !== 0.3】深入理解JavaScript中的数值类型

199 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情

前言

😎 不知道大家在面试的过程中有没有遇到这样的题目,为什么下面的代码会返回 false呢?

0.1 + 0.2 === 0.3;    // false

😎 亦或是下面这样的题目,为啥下面的代码会返回 true 呢?

var a = 2 / "fun";
typeof a === "number";    // true

🤓 在JavaScript中只有一种数值类型:number,而它则包括了整数和小数。

🤓 其实JavaScript没有真正意义上的整数,因为它的整数就是没有小数的十进制数。

var a = 123;
var b = 123.0;
a === b;   // true
  • JavaScript中的数值类型是基于 IEEE754 标准来实现的,该标准通常也被称为浮点数

语法

🧐 大家常用的十进制语法就不描述了,下面着重说一些特殊的语法。

var a = 0.123;
var b = .123;
  • 小数点前面的 0 是可以省略的
var a = 123.0;
var b = 123.;
  • 小数点后面的 0 也是可以省略的 从代码的可读性考虑,不建议这样写

toFixed方法

😮 此方法可指定小数部分的显示位数

var a = 123.45;

a.toFixed(0);    // "123"
a.toFixed(1);    // "123.4"
a.toFixed(2);    // "123.45"
a.toFixed(3);    // "123.450"
a.toFixed(4);    // "123.4500"
  • 你没有看错,toFixed 方法输出的接口实际上是给定数字的字符串形式

image.png

  • 如果小数部分显示位数多于实际位数,就用 0 补齐

😧 在上面的语法中我们知道小数点后面的 0 是可以省略的,那么下面这些情况是否都正常呢?

12.toFixed(3);

(12).toFixed(3);

0.12.toFixed(3);

12..toFixed(3);

image.png

在浏览器控制台中输出可以看出结果。

  • 12.toFixed(3); 是无效语法,因为 . 被视为 12. 的一部分,也就没有了去访问 toFixed方法的 .

  • 12..toFixed(3); 则是没问题的,可以正常输出结果的。这是以为第一个 . 被视为 number 中的一部分了,第二个 . 就是访问方法的

😩 还有一种语法也是正确的

12 .toFixed(3);

image.png

  • 不要忽略数字和 . 之间的空格了哦。(这样的语法只需要了解,在实际项目中不建议使用的)

0.1 + 0.2 !== 0.3

🤨 从一种正常人的思维亦或是从数学的角度来看这个题目,应该是返回 true,可在JavaScript中偏偏返回的是false,这是为什么呢?

😏 因为二进制浮点数中的 0.1 和 0.2 并不是十分精确,它们相加的结果是一个比较接近 0.3 的数字 0.30000000000000004,所以判断结果为 false

既然无法做到完全精确,那我们应该怎样去判断 0.1 + 0.2 是否等于 0.3 呢?

JavaScript中有一个误差范围值,也叫机器精度,这个值通常是 2^-52

目前大家常用的 ES6 中将误差范围值定义在 Number.EPSILON 中,我们可以直接使用

function numberEpsilonFun(n, m){
    return Math.abs(n - m) < Number.EPSILON;
}

var a = 0.1 + 0.2;
var b = 0.3;

numberEpsilonFun(a, b);    // true
numberEpsilonFun(0.0000001, 0.0000002);    // false

不是数字的数字

🤔 前言中有这样的一道题目,为什么最后返回的结果是 true 呢?

var a = 2 / "fun";
typeof a === "number";    // true
  • var a = 2 / "fun"; 返回值是 NaN

NaN 意思就是not a number - 不是一个数字,你可以理解为无效数值

NaN 虽然不是数字的数字,但它仍然是数字类型

var a = 2 / "fun";
a == NaN;    // false
a === NaN;    // false

😬 从上面的等式中可以看出 NaN 是一个特殊值,但它又不和自身相等

虽然我们不能直接判断它是否相等,但是可以使用一个工具函数来判断

var a = 2 / "fun";
isNaN(a);    // true

isNaN 函数也是有bug存在的,它判断的参数是否不是NaN,也不是数字

var a = 2 / "fun";
var b = "abc";

isNaN(a);    // true
isNaN(b);    // true
  • 很明显 abc 不是一个数字,也不是NaN

从 ES6 开始,我们可以使用 Number.isNaN() 这样一个工具函数来判断

if(!Number.isNaN){
    Number.isNaN = function(n){
        return n !== n;
    }
}

如果你仍在代码中使用 isNaN() ,那么你的代码迟早会出现 bug

总结一下

通过两道面试题带大家一起深入理解JavaScript中的数值类型,希望大家不仅会面试,还能让代码稳定运行~