JavaScript 中意想不到的时刻将挑战你对该语言的理解
JavaScript是世界上最流行的编程语言之一,被广泛用于构建动态交互式网站、Web 应用程序,甚至桌面和移动应用程序。JavaScript 因其广泛的应用和与各种平台的兼容性,成为了通往其他 Web 技术的门户。它已成为现代 Web 开发的基础语言。但它同时也是一种复杂的语言,其中存在许多意想不到的情况,即使是最有经验的开发人员也会感到困惑。
在本文中,我们将了解各种意想不到的 JavaScript 时刻,它们可能会让你感到困惑、考验你的极限,甚至让你感到沮丧。它也能帮助你改变你的编码方式。
你准备好让你的大脑爆炸了吗🤯?如果准备好了,那就让我们进入丛林吧。
1️⃣
2 == [2] // true
==
JS 中的运算符执行类型强制,这意味着它在进行比较之前尝试将要比较的值转换为常见数据类型。
在这个例子中,数字 2 被转换为字符串,数组[2]
也被转换为字符串。结果两个值都是2
。因此,比较结果为true
。
通常建议使用严格相等运算符===
而不是,以==
避免由于类型强制而导致意外结果。
探索更多:
'123' == 123 // true
'foo' == NaN // false
undefined == null // true
NaN === NaN // false
NaN == NaN // false
0 == null // false
2️⃣
[] == ![] // true
将一个空数组[]
与一个非空数组(使用运算符boolean
)求反后得到的值进行比较。比较的结果是,乍一看可能有点出乎意料。!
[]
true
在 JS 中,每个值在上下文中都可以是true
或。空数组是真值,这意味着它被视为处于上下文中。当我们对它应用运算符时,它会被转换为。false
boolean
true
boolean
!
false
另一方面,对boolean
非空数组求反后得到的值为。当我们使用运算符false
比较空数组(真值)和值(假值)时,JS 会执行类型约束,这意味着它会在比较之前尝试将值转换为通用类型。因此,空数组会被转换为 ,导致两边均为。最后,比较结果返回。false
==
false
false
true
探索更多:
['a', 'b'] !== ['a', 'b'] // true
['a', 'b'] == ['a', 'b'] // false
[1, 2] + [3, 4] // "1,23,4"
3️⃣
null == undefined // true
双等号==
运算符用于比较两个值是否相等,同时忽略它们的数据类型。当使用双等号运算符比较两个值时,null
它们undefined
被视为相等,比较结果为true
。这是因为 和 都null
表示undefined
缺少值,并且在这种情况下彼此等价。
使用严格相等运算符:
null === undefined // false
4️⃣
typeof NaN // number
typeof null // object
在 JS 中,typeof是一个用于确定值或变量类型的运算符。
NaN代表非数字,是 JS 中表示数字的特殊undefined
值unrepresentable
。
当你使用typeof
with时NaN
,它将返回number
。这可能看起来很奇怪,但这是因为NaN
从技术上讲,它在 JS 中是一种数字数据类型,即使它表示的实际上不是数字。
当typeof
应用于时null
,它返回字符串object
。这是因为null
被视为一个表示空对象引用的特殊值。null
本身不是对象,而是原始值。这被认为是 JS 语言设计中的一个怪癖或怪异之处。
探索更多:
typeof function(){} // "function"
null instanceof Object // false
5️⃣
true == "1" // true
false == "0" // true
JS 将 字符串 转换1
为boolean
值true
,并将 字符串0
转换为 ,false
因为任何非空字符串都被视为真值,反之则为假值。因此,比较变成了true == true
哪个是true
和false == false
哪个是true
。
探索更多:
1 + true // 2
1 - true // 0
'' == false // true
0 == false // true
true + false // 1
6️⃣
"1" + 1 // "11"
2 + "2" // "22"
"5" - 3 // 2
当将+ 运算符与 astring
和 a一起使用时number
,数字将转换为字符串并与该字符串连接。
如果string
可以解析为number
,它将从中减去。number
string
所以,"1" + 1
变成字符串"11"
2 + "2"
变成字符串"22"
"5" - 3
变成数字2
探索更多:
+"1" // 1
-"1" // -1
+true // 1
-true // -1
+false // 0
-false // -0
+null // 0
+undefined // NaN
1 / "2" // 0.5
"2" / 1 // 2
1 / 0 // Infinity
-1 / 0 // -Infinity
3 * "abc" // NaN
true > false // true
undefined + 1 // NaN
undefined - 1 // NaN
undefined - undefined // NaN
undefined + undefined // NaN
null + 1 // 1
null - 1 // -1
null - null // 0
null + null // 0
Infinity + 1 // Infinity
Infinity - 1 // Infinity
Infinity - Infinity // NaN
Infinity + Infinity // Infinity
Infinity / Infinity // NaN
7️⃣
"b" + "a" + + "a" + "a" // "baNaNa"
它将字符串b
、字符串a
、表达式产生的字符串+"a"
和字符串连接起来a
。
+"a"
强制将字符串a
转换为数字,因为不是有效数字,所以计算结果为NaN
(非数字) 。a
当我们连接b
、a
、NaN
(表示为空字符串)和 时a
,我们得到字符串baNaNa
。
8️⃣
!{} // false
{} == !{} // false
{} == {} // false
当我们将一个空对象{}
与一个取反的空对象进行比较时!{}
。感叹号!
是一个逻辑运算符,它对对象的值进行取反,因此!{}
返回结果false
,因为在 JS 中对象被视为真值。我们实际上是{}
在比较false
哪个结果为false
真,因为它们的值或数据类型不相等。
在最后一个表达式中,我们比较了两个空对象{}
。尽管它们看起来相同,但它们是两个独立的对象,在内存中具有不同的引用,因此它们的值或数据类型并不相等。最终,比较结果也会有一个false
值。
当在两个用花括号括起来的对象之间使用加号运算符 +{}
时,它会尝试将对象连接为字符串。
探索更多:
{} + [] === "" // false
!!{} // true
!![] // true
[] + [] // ""
[] + {} // "[object Object]"
{} + [] // "[object Object]"
{} + {} // "[object Object][object Object]"
[] == false // true
!!'' // false
!!0 // false
!!null // false
!!undefined // false
9️⃣
7 > 6 > 5 // false
首先,由于 7 大于 6,因此7 > 6
求值为 。 接下来,求值为 。在 JS 中,被强制代入数字,被强制代入。因此为,因为不大于。true
true > 5
true
1
false
0
1 > 5
false
1
5
所以最后,7 > 6 > 5
相当于true > 5
。false
探索更多:
5 < 6 < 7 // true
0 > null // false
1️⃣0️⃣
Math.max() // -Infinity
Math.min() // Infinity
Math.max()
&Math.min()
是分别可用于查找一组数字中的最大值和最小值的函数。
当不带任何参数调用时,Math.max()
返回-Infinity
代表 JS 中最小可能值的值number
,另一方面,Math.min()
返回代表JS 中Infinity
最大可能值的值。number
这种行为是有道理的,因为如果没有提供数字,就没有最大的数字可以返回Math.max()
,同样,也没有最小的数字可以返回Math.min()
1️⃣1️⃣
parseInt('08') // 8
parseInt('08', 10) // 8
parseInt('0x10') // 16
parseInt('08')
将字符串转换08
为整数8
。如果您这样写parseInt('08', 10)
,函数仍然会返回8
。
其背后的原因是,parseInt
函数的第二个参数是基数,它指定了要使用的计数系统。例如:binary
、、等等。如果未指定基数,则会尝试根据字符串格式检测基数。在上述情况下,由于以 开头,因此被视为八进制数,octal
因此它会被转换为十进制数。decimal
hexadecimal
parseInt
08
0
8
parseInt('0x10')
hexadecimal
将字符串转换0x10
为整数16
。基数也没有指定,但前缀0x
表示该数字应被视为数字,hexadecimal
因此它会被转换16
为十进制数。
探索更多:
parseFloat('3.14.15') // 3.14
parseFloat('0.0') // 0
1️⃣2️⃣
(function(x) { delete x; return x; })(1); // 1
一个接受参数 的匿名函数x
。在函数内部,它会尝试删除x
变量 ,但这是不可能的,因为x
是函数参数,无法删除。然后,该函数返回 的值x
。
当使用参数 调用此函数时,函数内部1
的值将被设置为。在这种情况下,删除操作不起作用,函数仅返回 的值,即x
1
x
1
1️⃣3️⃣来自 DEV 社区的
@tohodo为这篇文章补充了一个很棒的观点。我们来看看吧……
for (var i = 0; i < 3; ++i) {
setTimeout(() => console.log(i), 1000); // returns 3 three times
}
for (let i = 0; i < 3; ++i) {
setTimeout(() => console.log(i), 1000); // returns 0 1 2
}
这是因为var
在函数作用域中创建了单个绑定,所以在一秒超时后,循环已经运行完毕,因此你得到了3
三次。通过使用let
,你将变量绑定到块作用域(循环),因此它返回你期望的值,因为它i
指的是该循环迭代时的值。
感谢@tohodo分享这一见解。
探索和理解这些 JavaScript 概念,你做得真棒!这些知识绝对能帮你应对面试,并让你作为面试官能够评估潜在候选人的技能。继续努力,继续学习!Ctrl+N
❤ 动机:
🍀支持
请考虑关注并支持我们,订阅我们的频道。非常感谢您的支持,这将帮助我们继续创作您喜爱的内容。提前感谢您的支持!
文章来源:https://dev.to/codeofrelevancy/unexpected-moments-of-javascript-that-will-challenge-your-understanding-of-the-language-4834