专栏名称: 程序员鱼皮
鹅厂全栈开发,持续分享编程技法和实用项目
目录
相关文章推荐
阑夕  ·  倒也没毛病-20250212193911 ·  19 小时前  
河北交通广播  ·  河北5市已明确:时间延长! ·  19 小时前  
界面新闻  ·  受AI冲击,网文译者收入缩水近半 ·  昨天  
萧秋水  ·  手工制作是如何成了我的快乐制造机 ·  昨天  
界面新闻  ·  印度终止对中国“工业大米”的反倾销调查 ·  2 天前  
51好读  ›  专栏  ›  程序员鱼皮

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

程序员鱼皮  · 公众号  ·  · 2024-06-07 11:39

正文

本文来分享一些前端 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.EPSILON Math.round toFixed 等方法来比较浮点数或将其格式化为固定小数位数。如果需要精确计算,并且不能容忍这种舍入误差,可以使用特殊的库,如 decimal.js bignumber.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() 方法,也就是上面的第一种写法。







请到「今天看啥」查看全文


推荐文章
阑夕  ·  倒也没毛病-20250212193911
19 小时前
河北交通广播  ·  河北5市已明确:时间延长!
19 小时前
视觉艺术摄影  ·  性感私房照,就得这样拍
7 年前
爱丽丝手札  ·  中等收入陷阱就是伪命题!
7 年前