关于数字的前端面试题

写在前面,总结面试题不一定是为了准备面试,更是对于自己的一种温故知新,了解自己知识的熟练度和理解度。

问题一览

  1. 如何判断一个值是否为NaN?运行环境内建的方法isNaN()有坑
  2. 如何判断两个浮点数相等?如fn(0.1+0.2 , 0.3) => { /*返回true*/}
  3. 如何检测一个值是否整数?
  4. 对于一个数字进行取整,你能说出多少种方法?
  5. 当一个变量显式类型转换时(利用Number()方法),遵循的规则是什么?
  6. Number([])和Number([1,2,3])的值分别是什么?说明其原理?
  7. 讲一讲parseInt()方法遵循的运算规则?

问题解答

1.如何判断一个变量是否为NaN?

相信大多数人应该都会想到这个不就用运行环境提供的内建方法 isNaN()来判断吗?

如下面的代码:

事实上,isNaN的逻辑是“输入参数是否不是NaN,也不是数字”。这句话是在《你不知道的JavaScript(中卷)》 2.4.3中提到的,我理解isNaN()的逻辑可以理解为“输入参数是否可以转化为数字”更加贴切和容易理解。所以字符串“666”的返回值为true,因为他可以转化为数字,而字符串“what?”不能转换为数字,故返回值为false。

那既然无法用isNaN来检测一个值是否为NaN,那么该如何做?

有两种办法

第一种,根据上面的实验,我们可以先判断输入参数的类型是否为number,再调用isNaN方法,这样就避免了对于非数字类型的判断错误。代码如下:

第二种,利用NaN的一个特性,它是JS语言中唯一一个不等于他本身的值,所以我们也可以这么写。

还有一种,可以利用ES6中提供的Object.is()方法来进行验证

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

2.如何判断两个浮点数相等?

在JavaScript中,0.1+0.2 不等于0.3是一个经典问题,他时刻提醒你,对于浮点数来说,他并不能像普通数学题那样简单比较。究其原因,是因为在JS中,0.1+0.2的值是一个比较接近0.30000000000000004的数字,所以他并不等于0.3。

不要小看这个问题,浮点数的运算经常会出现,比如计算商品的折扣、计算税费等情况下都需要对浮点数进行运算。

通常的做法是设置一个误差范围值,通常称为“机器密度”,对于JavaScript来说,这个值是2的-52次幂,即Math.pow(2, -52)。

所以,可以对于浮点数进行比较时可以用下面的方法(在ES6中,Number.EPSILON是自带的),以下代码示例来源于《你不知道的JavaScript(中卷)》2.3.2

此外,需要说明的是JavaScript中最大的浮点数是Number.MAX_VALUE和Number.MIN_VALUE。

3.如何检测一个值是否整数

如果允许使用ES6的话,可以用Number.isInterger();这个方法干净利落。

如果不允许使用ES6的话,可以自行写一个pollyFill方法。

4.对于一个数字进行取整,你能说出多少种方法?

parseInt()这个方法你肯定能想到。但你可能想不到他的坑还真不少,未必是无懈可击的方法。

在最后一个问题中,我在详细解答。

其实还有很多很简单有效的方法来对数字进行取整。

比如下面的方法:

这三种方法都是可以的,分别说一下:

8.84|0或者 写成0 | 8.84 都是一样的,从语法上看,他是让0与指定值进行按位“或”运算,在JavaScript中,它先对指定值执行了ToInt32的转换,在按位进行或运算,所以最终结果就是把指定值转换为32位的整数。

而~~8.84也是对变量进行ToInt32的转换;再进行一步按位“取非”运算,即对每个字节进行反转;然后,再对结果再次“取非”。

那么8.84>>0的操作就同理可证了……

但是,上面的三种方法也是有其局限性的,因为他们是遵循ToInt32的转化规范,所以他们也只能对于32位的数字进行转换,所以再加上一个符号位,那么他们所能处理的数字范围在2的正负31次幂之间,即-2147483648 ≤ x ≤ 2147483647。

5.当一个变量显式类型转换时(利用Number()方法),遵循的规则是什么?

这个问题应该会有很多种文法,比如,把一个字符串转换为数字时,都经历了哪些操作?

这道题还是很考验基础的,一般工程师是不会记住这个细节点的。

言归正传,ES5规范中规定了这个抽象操作ToNumber。

对于布尔型:true的结果为1,false的结果为0;

对于undefined: 结果为NaN

对于null:结果为0

对于字符串类型:遵循数字常量的相关规则和语法。处理失败时会返回NaN。

对于复杂类型:会先调用该值得valueOf()方法,如果有并且返回基本类型之,就是用该值进行强制类型转换。如果没有就是使用toString()的返回来进行强制类型转换。

举个例子来加强一下记忆:

6.Number([])和Number([1,2,3])的值分别是什么?说明其原理?

这道题应该也算是上一道题的加强记忆了。

大家已经知道了是先调用valueOf(),再调用toString()方法,那么空数组和[1,2,3]有什么区别呢?

因为数字的valueOf()方法返回的是数组本身,不是一个基本类型,所以还会调用toString()方法;而数组的toString()方法返回的是数组各项通过逗号拼接一起的字符串(可以理解调用了Array.prototype.join(",")方法),所以空数组返回空字符串,转换为数组自然就是0;而数组[1,2,3]则只能转换为NaN了.

那么,大家觉得下面的代码应该输出什么呢?为什么?

7.讲一讲parseInt()方法遵循的运算规则?

之前已经提到了,parseInt()方法含有太多坑。也许面试者会问你下面的代码为什么可以输出52

如果想回答上面的问题,你必须知道下面的知识点。

parseInt(string, radix);方法的接受两个参数:

  • string:

要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。

  • radix:

一个介于2和36之间的整数(数学系统的基础),表示上述字符串的基数。比如参数"10"表示使用我们通常使用的十进制数值系统。始终指定此参数可以消除阅读该代码时的困惑并且保证转换结果可预测。当未指定基数时,不同的实现会产生不同的结果,通常将值默认为10。

返回值:

返回解析后的整数值。 如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN。

如果 parseInt 遇到了不属于radix参数所指定的基数中的字符那么该字符和其后的字符都将被忽略。接着返回已经解析的整数部分。

所以,这里就明白为什么字符串'52px'会被parseInt()解析为52,因为没有传递第二个参数radix,所以默认按照10进制进行解析,而字符'p'不在10进制内,所以字符'p'和后面的字符全部被忽略,直接返回数字52.

下面是parseInt()最经典的一个坑:

如果不亲自一试,你绝不会相信上面代码的输出是18。

这里需要知道的是,1/0运算结果是“无穷”,在JavaScript中为Infinity,而这个Infinity转换为字符串则为'Infinity',第一个字符是'I',在以19为基数时他的值为18。第二个字符‘n’不是一个有效的数字字符,所以除第一个字符外,后面的字符全部被忽略,所以最后就返回了18。

原文发布于微信公众号 - 较真的前端(gh_7af41a2be77e)

原文发表时间:2017-11-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏从流域到海域

《笨办法学Python》 第19课手记

《笨办法学Python》 第19课手记 本节课讲函数和变量(变量和函数的关系是变量作为做函数的参数,定义时是形参,使用时是实参),内容比较简单。 源代码如下: ...

24210
来自专栏nummy

python堆排序heapq

堆是一种树形数据结构,其中子节点与父节点之间是一种有序关系。最大堆中父节点大于或等于两个子节点,最小堆父节点小于或等于两个子节点。Python的heapq模块实...

2063
来自专栏我是攻城师

理解插入排序,希尔排序,选择排序的算法原理

在前面的文章中,其实已经把效率比较高的排序算法给分析过了,比如比较通用的快排,归并排序和堆排,还有用于特定场景的计数排序等。本篇我们把剩下的几种效率一般的排序算...

991
来自专栏HTML5学堂

操作符与数据类型转换

上一期堡堡给大家讲解了关于JS的基础语法,虽然是一些非常基础的知识,但是它对大家的后期学习奠定了一定的基础。知识像一张网,基础越扎实,网住的鱼就越多,要告诉大家...

3098
来自专栏青玉伏案

在Objective-C中浅谈面向对象

  接触面向对象也有一段时间了,当时是通过C++学习的OOP,后来又接触到了PHP和Java。每种OOP的语言在面向对象上或多或少都会有不同的地方,现在在学习O...

1856
来自专栏C语言C++游戏编程

有人@我,你有一份C语言基础大全手册要领取,快来拿!

前两天,有网友问了我一个关于C语言的问题,本着认真装逼的态度,我把大学时学过的C语言课本翻了一遍,终于找到了答案。整理后,现分享给大家!

1362
来自专栏java一日一条

JavaScript 函数式编程中的 curry 实现

最近在学习javascript函数式编程,对其中大名鼎鼎的curry十分感兴趣,curry函数可以接受一个函数,我们暂且称之为原始函数,返回的也是一个函数,柯里...

854
来自专栏程序员互动联盟

【编程基础】C++ Primer快速入门之七:运算符

一、表达式的定义 什么是表达式?表达式,是由数字、运算符、数字分组符号(括号)、自由变量和约束变量等以能求得数值的有意义排列方法所得的组合(1)。1 + 2是个...

3114
来自专栏CDA数据分析师

Python面试中8个必考问题

1、下面这段代码的输出结果是什么?请解释。 ? 怎样修改extendList的定义能够产生以下预期的行为? 上面代码输出结果将是: ? 很多人都会误认为list...

20010
来自专栏木子昭的博客

正则 (入门篇)简单来说写好正则表达式的两个要点:写在最后

如果你对正则感兴趣,读完这篇文章,一定会有收获~_^ 简单来说 正则一般代指正则表达式 正则表达式是从"复杂数据"中抽取"有用数据"的公式 ---- 写好正则...

3068

扫码关注云+社区

领取腾讯云代金券