JavaScript 中这些离谱的设计,你知道几个?

游客2024-06-17 03:24:07

本文来分享一些中离谱的设计,这种设计日常开发遇见的机率可能比较小,但笔试可能会问到噢!

(0.)

答案: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

 

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

 

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

 

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

[]==![]

答案:true

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

[]是一个空链表,它是真值。![]是false,由于当将空链表强制转换为布尔值时,它变为true,之后被否定为false。为此,比较弄成了[]==false。

当比较不同类型时,将尝试将一个或两个值强制转换为相同类型。在这些情况下,它将尝试将字段强制转换为原始值。

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

如今,尝试将布尔值false转换为数字,即0,表达式就弄成了""==0。

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

NaN===NaN

答案:false

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

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

 

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

 

[1,2]+[3,4]

答案:"1,23,4"

在中,当尝试使用+运算符来联接两个字段,实际上并不会执行链表的拼接或合并。相反,因为+运算符在中既可以用作乘法运算符(对于数字),也可以用作字符串联接运算符(对于字符串),因而链表会首先被转换为字符串,之后再进行联接。

链表到字符串的转换是通过调用链表的()方式实现的,这一般会生成一个由链表元素组成的冒号分隔的字符串。为此,[1,2]会被转换为"1,2",而[3,4]会被转换为"3,4"。之后,这两个字符串会被+运算符联接上去,得到"1,23,4"。所以,[1,2]+[3,4]的结果是"1,23,4"。

假如想要合并两个字段,应当使用链表的()方式或扩充运算符如下所示:

 

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

 

 

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

 

null

答案:。

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

 

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

 

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

try...

答案:2

 

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

 

在中,当在一个函数(包括箭头函数)的try块和块中都有句子时,块中的句子会覆盖try块中的句子。这是由于块总是会被执行,无论try块中的代码是否成功执行,或则是否抛出了异常。并且,假如块中有句子,这么这个句子将决定整个函数的返回值。

0.14*100

答案:14.0002

 

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

 

在中,所有的数字都是以64位浮点数方式储存的,虽然它们被申明为整数。因为二补码难以精确表示所有的十补码小数,因而在进行浮点数运算时,可能会出现精度问题。因为在二补码浮点数表示中,0.14不能精确表示,因而在进行加法运算时会出现微小的舍入偏差。一个精典的问题就是0.1+0.2不等于0.3。这两个问题出现的缘由是一样的。

 

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

 

为了处理这些精度问题,可以使用.和Math.round、等方式来比较浮点数或将其低格为固定小数位数。假如须要精确估算,但是不能容忍这些舍入偏差,可以使用特殊的库,如.js或.js,它们提供了高精度的十补码数运算。

1.()

答案:报错

 

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

 

在中,1.()会造成一个句型错误,由于点号(.)在这儿被解析为浮点数的一部份,但紧接着并没有另一个数字来产生有效的浮点数字面量,所以解析器会抛出一个:ortoken错误。

但是,当写1..()时,情况就不同了。这儿有两个点号,但第一个点号实际上并不是浮点数的一部份。这是由于的解析器在碰到连续的点号时会将它们视为一种特殊的句型结构,即第一个点号被视为数字1的结尾(虽然在这儿它并没有实际意义,由于1早已是完整的数字),而第二个点号则作为访问对象属性的操作符。

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

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

因为紧接着有一个点号,但它并没有追随另一个数字来产生浮点数,所以它被解释为对象属性的访问操作符。

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

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

所以,1..()最终会返回字符串"1",虽然这些写法在实际编程中并不常见,由于它可能会导致混淆。更常见的做法是直接对数字变量使用.()方式,也就是前面的第一种写法。

Math.max()

答案:true

 

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

 

在标准的环境中,Math.max()在没有参数时应当返回-,而Math.min()在没有参数时应当返回。并且,因为总是小于-,所以Math.max()

90992===90993

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

当尝试使用小于.的整数时,会尝试将其储存为一个近似的浮点数,这可能会造成精度损失。在这个事例中,90992和90993就会被转换为近似的浮点数,但因为精度限制,这两个数字可能会表示为相同的浮点数值。

为此,假如须要在中表示大数字时,建议使用字符串来储存大数,以防止精度遗失。