首页 > 其他分享 >前端的隐藏巨坑,遇到了就自认倒霉吧。。

前端的隐藏巨坑,遇到了就自认倒霉吧。。

时间:2024-06-07 11:58:42浏览次数:27  
标签:JavaScript 数字 前端 巨坑 NaN toString 字符串 自认倒霉 浮点数

本文来分享一些前端 JavaScript 中离谱的设计,这些设计日常开发遇到的概率可能比较小,而且一旦在开发中遇到了,大概率只能自认倒霉了。

所以建议朋友们认真阅读本篇文章,应该能涨不少知识~

学前端的朋友们,看看以下设计你了解过几个呢?

parseInt(0.0000005)

答案:5

parseInt(0.5); // -> 0
parseInt(0.05); // -> 0
parseInt(0.005); // -> 0
parseInt(0.0005); // -> 0
parseInt(0.00005); // -> 0
parseInt(0.000005); // -> 0
parseInt(0.0000005); // -> 5

parseInt 函数将其第一个参数转换为字符串(如果它还不是字符串),然后再转换为数字。当将 0.0000005 转换为字符串时,会得到以下结果:

String(0.0000005); // -> "5e-7"

然后 parseInt 函数只取该字符串的第一个字符,即 5,并将其解析为一个数字。

[] == ![]

答案:true

[] == ![] 之所以返回 true,是因为比较过程中发生了隐式的类型转换。下面来逐步解析:

  1. [] 是一个空数组,它是真值。![]false,因为当将空数组强制转换为布尔值时,它变为 true,然后被否定为 false。因此,比较变成了 [] == false

  2. 当比较不同类型时,JavaScript 将尝试将一个或两个值强制转换为相同类型。在这种情况下,它将尝试将数组强制转换为原始值。

  3. 一个空数组,当被强制转换为原始值时,变成了一个空字符串 ""。因此,表达式 [] == false 实际上变成了 "" == false

  4. 现在,JavaScript 尝试将布尔值 false 转换为数字,即 0,表达式就变成了 "" == 0

  5. 根据 JavaScript 的规则,当比较一个字符串和一个数字时,字符串将被强制转换为数字。因此,"" 被强制转换为数字后变成了 0。这时比较的就是 0 == 0,结果是 true

NaN === NaN

答案:false

在 JavaScript 中,NaN(Not a Number)是一个特殊的值,表示一个非数字的值。然而,当使用 ===(严格相等运算符)来比较 NaN 时,会出现一个特殊的情况:NaN 并不等于 NaN。具体来说,NaN === NaN 的结果是 false,尽管两者都是 NaN。这是因为在 IEEE 754 浮点数标准中,NaN 被定义为不等于任何其他值,包括它自身。

要检查一个值是否是 NaN,通常使用 isNaN() 函数,但请注意,isNaN() 对于非数字类型的参数(如字符串或对象)也可能返回 true,因为它会尝试将这些参数转换为数字。更严格的检查方法是使用 Number.isNaN(),它只有在参数确实是 NaN 时才返回 true。

NaN === NaN // false  
isNaN(NaN);  // true,但这不是最佳方式  
Number.isNaN(NaN); // true,这是更好的方式

[1, 2] + [3, 4]

答案:"1,23,4"

在 JavaScript 中,当尝试使用 + 运算符来连接两个数组,实际上并不会执行数组的拼接或合并。相反,由于 + 运算符在 JavaScript 中既可以用作加法运算符(对于数字),也可以用作字符串连接运算符(对于字符串),因此数组会首先被转换为字符串,然后再进行连接。

数组到字符串的转换是通过调用数组的 toString() 方法实现的,这通常会生成一个由数组元素组成的逗号分隔的字符串。因此,[1, 2] 会被转换为 "1,2",而 [3, 4] 会被转换为 "3,4"。然后,这两个字符串会被 + 运算符连接起来,得到 "1,23,4"。所以,[1, 2] + [3, 4] 的结果是 "1,23,4"

如果想要合并两个数组,应该使用数组的 concat() 方法或扩展运算符如下所示:

  • 使用 concat() 方法:

const result = [1, 2].concat([3, 4]); // [1, 2, 3, 4]
  • 使用扩展运算符:

const result = [...[1, 2], ...[3, 4]]; // [1, 2, 3, 4]

typeof null

答案:object

在 JavaScript 早期版本中,所有值都存储在 32 位的单元中,每个单元包含一个小的 类型标签(1-3 bits) 以及当前要存储的数据。类型标签共有五种类型:

000: object   - 数据类型为 对象。
  1: int      - 数据类型为 有符号整数。
010: double   - 数据类型为 双精度的浮点数。
100: string   - 数据类型为 字符串。110: boolean  - 数据类型为 布尔值。

null 的值是机器码 NULL 指针(指针值是000),也就是说null的类型标签也是 000,和object的类型标签一样,所以会被判定为object

try...finally

答案:2

(() => {  
  try {    
    return 1;
  } finally {
    return 2;
  }
})();

在JavaScript中,当在一个函数(包括箭头函数)的try块和finally块中都有return语句时,finally块中的return语句会覆盖try块中的return语句。这是因为finally块总是会被执行,无论try块中的代码是否成功执行,或者是否抛出了异常。而且,如果finally块中有return语句,那么这个return语句将决定整个函数的返回值。

0.14 * 100

答案:14.000000000000002

0.13 * 100   // 13
0.14 * 100   // 14.000000000000002
0.15 * 100   // 15
0.16 * 100   // 16

在JavaScript中,所有的数字都是以 64 位浮点数形式存储的,即使它们被声明为整数。由于二进制无法精确表示所有的十进制小数,因此在进行浮点数运算时,可能会出现精度问题。由于在二进制浮点数表示中,0.14 不能精确表示,因此在进行乘法运算时会出现微小的舍入误差。一个经典的问题就是 0.1 + 0.2 不等于 0.3。这两个问题出现的原因是一样的。

0.1 + 0.2 === 0.3  // false
0.1 + 0.5 === 0.6  // true

为了处理这种精度问题,可以使用Number.EPSILONMath.roundtoFixed等方法来比较浮点数或将其格式化为固定小数位数。如果需要精确计算,并且不能容忍这种舍入误差,可以使用特殊的库,如decimal.jsbignumber.js,它们提供了高精度的十进制数运算。

1.toString()

答案:报错

const num = 1; 
num.toString() // 1
1.toString();  // Uncaught SyntaxError: Invalid or unexpected token
1..toString(); // 1

在 JavaScript 中,1.toString() 会导致一个语法错误,因为点号(.)在这里被解析为浮点数的一部分,但紧接着并没有另一个数字来形成有效的浮点数字面量,所以解析器会抛出一个 Uncaught SyntaxError: Invalid or unexpected token 错误。

然而,当写 1..toString() 时,情况就不同了。这里有两个点号,但第一个点号实际上并不是浮点数的一部分。这是因为 JavaScript 的解析器在遇到连续的点号时会将它们视为一种特殊的语法结构,即第一个点号被视为数字 1 的结尾(尽管在这里它并没有实际意义,因为 1 已经是完整的数字),而第二个点号则作为访问对象属性的操作符。

因此,1..toString() 实际上是这样被解析的:

  1. 数字 1 被解析为一个完整的数字字面量。

  2. 由于紧接着有一个点号,但它并没有跟随另一个数字来形成浮点数,所以它被解释为对象属性的访问操作符。

  3. 因为 1 在 JavaScript 中是一个原始值,它本身并没有 .toString() 方法,但是在这里,由于点号操作符的存在,JavaScript 会尝试将 1 转换为一个 Number 对象(这是一个称为装箱或自动封装的过程)。

  4. 一旦 1 被转换为 Number 对象,就可以调用它的 .toString() 方法了。

所以,1..toString() 最终会返回字符串 "1",尽管这种写法在实际编程中并不常见,因为它可能会引起混淆。更常见的做法是直接对数字变量使用 .toString() 方法,也就是上面的第一种写法。

Math.max() < Math.min()

答案:true

Math.max() < Math.min() // true
Math.max() // -Infinity
Math.min() // Infinity

在标准的 JavaScript 环境中,Math.max() 在没有参数时应该返回 -Infinity,而 Math.min() 在没有参数时应该返回 Infinity。但是,由于 Infinity 总是大于 -Infinity,所以 Math.max() < Math.min() 返回 true。

9007199254740992 === 9007199254740993

答案:trueJavaScript 的 Number 类型是基于 IEEE 754 标准 (也称为 64 位浮点数)实现的,这意味着它有一些限制,特别是关于可以精确表示的数字的范围和精度。在 IEEE 754 标准中,最大的安全整数(即可以精确表示的最大整数)是 Number.MAX_SAFE_INTEGER,其值为 9007199254740991(2 的 53 次方减 1)。

当尝试使用大于 Number.MAX_SAFE_INTEGER 的整数时,JavaScript 会尝试将其存储为一个近似的浮点数,这可能会导致精度损失。在这个例子中,90071992547409929007199254740993 都会被转换为近似的浮点数,但由于精度限制,这两个数字可能会表示为相同的浮点数值。

因此,如果需要在 JavaScript 中表示大数字时,建议使用字符串来存储大数,以避免精度丢失。

来自-前端充电宝,欢迎大家关注!
 

在线备战面试、刷题指南,拿走不谢,要学会站在别人的肩膀上提升自己点击这里-->

最后:

 如果你现在正在找工作,可以私信“web”或者直接添加下方小助理进群领取前端面试小册、简历优化修改、大厂内推以及更多阿里、字节大厂面试真题合集,和p8大佬一起交流。

标签:JavaScript,数字,前端,巨坑,NaN,toString,字符串,自认倒霉,浮点数
From: https://blog.csdn.net/Likestarr/article/details/139523119

相关文章

  • 前端柯里化
    柯里化(Currying)是一种处理函数参数的方法,它的基本原理是将一个具有多个参数的函数转换为一些嵌套的一元函数(每个函数只接收一个参数)。这里有一个简单示例来展示如何在JavaScript中实现柯里化:假设我们有一个求和函数sum,接收两个参数a和b,返回它们的和:constsum=(a,b......
  • 【管理咨询宝藏124】通过BLM打通前端业务与财务的双轨制设计方案
    本报告首发于公号“管理咨询宝藏”,如需阅读完整版报告内容,请查阅公号“管理咨询宝藏”。【管理咨询宝藏124】通过BLM打通前端业务与财务的双轨制设计方案【格式】PDF版本【关键词】BLM、组织架构设计、流程优化【核心观点】-运用“拉通业务财务的SP模型”,讲清楚财务目......
  • 前端工程化工具系列(八)——Commitizen(v4.3.0):Git提交规范化工具
    在前端工程化工具系列(四)——Commitlint(v19.3.0):规范化Git提交中曾介绍过commitlint,它主要负责检查提交信息的规范性。而本文中的commitizen,则是提供给了一个交互式的命令行界面,引导开发者按照预定义的格式填写提交信息。它俩的目的都是规范git提交。按照使用习惯......
  • 前端 危!!! 这个项目可以一键图片转代码
       这段时间来,AI已经逐步走进我们的工作和生活,作为程序员来说,让AI写代码已经成为稀松平常的操作了,今天给大家介绍一个更牛逼的操作,屏幕截屏转化为代码,从此前端开发更简单screenshot-to-codescreenshot-to-code可以将任何屏幕截图或设计转换为干净的代码,它是一个简单的工......
  • 前端 JS 经典:阿里云文件上传思路
    前言:功能点概括:1、多选文件2、选择文件夹3、拖拽4、选择后形成一个列表,列表里有一些信息5、有进度条6、控制并发数7、可取消8、展示统计信息1.交互实现交互的目标是要拿到file对象。只要拿到file对象,就能通过网络上传。1.1如何选择多文件给input添加multip......
  • 微前端学习笔记(5):从import-html-entry发微DOM/JS/CSS隔离
    import-html-entry 是qiankun中一个举足轻重的依赖,用于获取子应用的HTML和JS,同时对HTML和JS进行了各自的处理,以便于子应用在父应用中加载。 import-html-entry主要是实现了以下几个能力拉取url对应的html并且对html进行了一系列的处理拉取上述html中所......
  • 前端开发学习路径
    前端开发学习路径里程碑一:HTML初探(掌握网页结构)任务:理解HTML的基本概念,例如标签、元素、属性等。掌握常用的HTML标签,例如<h1>​-<h6>​、<p>​、<a>​、<img>​、<div>​、<span>​、<ul>​、<ol>​、<li>​、<table>​等。能够使用HTML创建简单的网页,例如个......
  • 微前端学习笔记(1):微前端总体架构概述,从微服务发微
    从最初的CS架构,如MFCJavaSwing等,到BS架构,JSPPHP,再到前端后端分离,前端从jquery  GWT-Ext 到Handlebars,再到angularJS/Vue/React,反观java世界,学好SpringMyBatis,一路无忧,哎…… 微服务为了解决庞大的一整块后端服务带来的变更与扩展方面的限制,出现了微服务架构(Mic......
  • 微前端学习笔记(3):前端沙箱之JavaScript的sandbox(沙盒/沙箱)
    sandboxSandbox(沙盒/沙箱)的主要目的是为了安全性,以防止恶意代码或者不受信任的脚本访问敏感资源或干扰其他应用程序的执行。通过在沙盒环境中运行,可以确保代码的行为被限制在一个安全的范围内,防止其超出预期权限进行操作。沙箱(Sandbox)是一种安全机制,目的是让程序运行在一个相对......
  • 微前端学习笔记(4):从微前端到微模块之EMP与hel-micro方案探索
    ModuleFederation是啥?ModuleFederation就是一个JavaScript远程模块加载架构,即:ModulefederationallowsaJavaScriptapplicationto dynamicallyruncodefromanotherbundle/build, onbothclientandserver。  它允许将一个应用程序的某些模块打包为一个独立的、......