[] == ![][] == false
现在让我们继续了解 == 运算符 。每当使用 == 运算符比较 2 个值时 , JavaScript 就会执行抽象相等比较算法 。
该算法有以下步骤:
文章插图
正如您所看到的 , 该算法考虑了比较值的类型并执行必要的转换 。
对于我们的例子 , 我们将 x 表示为 [] , 将 y 表示为 ![] 。我们检查了 x 和 y 的类型 , 发现 x 是对象 , y 是布尔值 。由于 y 是布尔值 , x 是对象 , 因此应用抽象相等比较算法中的条件 7:
如果 Type(y) 为 Boolean , 则返回 x == ToNumber(y) 的比较结果 。
这意味着如果其中一种类型是布尔值 , 我们需要在比较之前将其转换为数字 。ToNumber(y) 的值是多少?正如我们所看到的 , [] 是一个真值 , 否定则使其为假 。结果 , Number(false)为0 。
[] == false[] == Number(false)[] == 0
现在我们有了比较 [] == 0 , 这次条件 8 开始发挥作用:如果 Type(x) 是 String 或 Number 并且 Type(y) 是 Object , 则返回比较结果 x == ToPrimitive(y) 。
基于这个条件 , 如果其中一个操作数是对象 , 我们必须将其转换为原始值 。这就是 ToPrimitive 算法发挥作用的地方 。我们需要将 [] x 转换为原始值 。数组是 JavaScript 中的对象 。正如我们之前所看到的 , 当将对象转换为基元时 , valueOf 和 toString 方法就会发挥作用 。
在这种情况下 , valueOf 返回数组本身 , 它不是有效的原始值 。因此 , 我们转向 toString 进行输出 。将 toString 方法应用于空数组会得到一个空字符串 , 这是一个有效的原语:
[] == 0[].toString() == 0"" == 0
将空数组转换为字符串会得到一个空字符串“” , 现在我们面临比较:“”== 0 。现在 , 其中一个操作数是字符串类型 , 另一个操作数是数字类型 , 则条件 5 成立:
如果 Type(x) 是 String 并且 Type(y) 是 Number , 则返回比较结果 ToNumber(x) == y 。
因此 , 我们需要将空字符串“”转换为数字 , 即为 0 。
"" == 0ToNumber("") == 00 == 0
最后 , 两个操作数具有相同的类型并且条件 1 成立 。由于两者具有相同的值 , 因此 , 最终输出为:0 == 0 // true
到目前为止 , 我们在探索的最后几个问题中使用了强制转换 , 这是掌握 JavaScript 和在面试中解决此类问题的重要概念 , 这些问题往往会被问到很多 。 8、闭包这是与闭包相关的最著名的面试问题之一:
const arr = [10, 12, 15, 21];for (var i = 0; i < arr.length; i++) {setTimeout(function() {console.log('Index: ' + i + ', element: ' + arr[i]);}, 3000);}
如果您知道输出 , 那就好了 。那么 , 让我们尝试理解这个片段 。从表面上看 , 这段代码片段将为我们提供以下输出:Index: 0, element: 10Index: 1, element: 12Index: 2, element: 15Index: 3, element: 21
但这里的情况并非如此 。由于闭包的概念以及 JavaScript 处理变量作用域的方式 , 实际的输出会有所不同 。当延迟 3000 毫秒后执行 setTimeout 回调时 , 它们都将引用同一个变量 i , 循环完成后该变量的最终值为 4 。结果 , 代码的输出将是:Index: 4, element: undefinedIndex: 4, element: undefinedIndex: 4, element: undefinedIndex: 4, element: undefined
出现此行为的原因是 var 关键字没有块作用域 , 并且 setTimeout 回调捕获对同一 i 变量的引用 。当回调执行时 , 它们都会看到 i 的最终值 , 即 4 , 并尝试访问未定义的 arr[4] 。为了实现所需的输出 , 您可以使用 let 关键字为循环的每次迭代创建一个新范围 , 确保每个回调捕获 i 的正确值:
const arr = [10, 12, 15, 21];for (let i = 0; i < arr.length; i++) {setTimeout(function() {console.log('Index: ' + i + ', element: ' + arr[i]);}, 3000);}
通过此修改 , 您将获得预期的输出:Index: 0, element: 10Index: 1, element: 12Index: 2, element: 15Index: 3, element: 21
使用 let 在每次迭代中为 i 创建一个新的绑定 , 确保每个回调引用正确的值 。
推荐阅读
- 高级分析可以帮助快速检测内部威胁
- 《第八个嫌疑人》首映!观众评价一边倒,理由出奇一致
- 《第八个嫌疑人》首映,张颂文缺席、孙阳内八,观众评价引热议
- 九月钓鱼最好用的几种饵料,针对各种鱼情
- 当代资本审美与煤老板审美哪个更高级?同一角色对比下,差距明显
- 吃素菜的八个误区
- 庾澄庆回应《好声音》50W转腚费!承认李玟被针对,话里有话
- 对付高级绿茶的最好方法
- 威尼斯电影节红毯秀盘点,国内外女星大PK ,高级感slay全场
- 文艺高逼格的店铺名字 高级文艺有创意的店铺名