javascript - 为什么 Javascript 以这种方式工作?
问题描述
所以我在推特上看到了某人的推文,提到下面的脚本是在面试时给出的。
for (var i = 0; i < 3; i+=1) {
setTimeout(function() {
console.log(i)
}, 100)
}
受访者被要求预测这个剧本的结果,他在推文中提到这对他来说是显而易见的。
对我来说,作为对 Javascript 的全新(或不感兴趣),很难理解为什么结果不是:
1) 0、1、2 顺序。(作为传统的'for-loop')
2)。3 只打印一次。(如果在调用函数之前迭代完全完成)
但打印 3 三遍。
这是因为 Javascript 不是顺序编程语言,或者 Javascript 的特性,还是两者兼而有之?
解决方案
要理解这一点,您需要了解 JavaScript 如何基于事件以及范围如何工作,这就是为什么我认为它被用作面试问题的原因。
基本上,JavaScript 是基于事件队列的。在提供的示例代码中,setTimeout
不会立即执行代码,而是让引擎知道代码应该在 100 毫秒内触发。
但是,for
循环会立即执行。如果您使用块范围的变量定义,这本身不会有问题,例如let i = 0
. 例如,以下代码将打印 0、1、2:
for (let i = 0; i < 3; i+=1) {
setTimeout(function() {
console.log(i)
}, 100)
}
但是,在代码var
中使用,它被“提升”到函数定义的顶部,或者在这种情况下,是片段/文件的顶部。所以实际上,代码在引擎看来如下所示:
var i;
for (i = 0; i < 3; i+=1) {
setTimeout(function() {
console.log(i)
}, 100)
}
这有一个有趣的效果:现在 for 循环运行了 3 次,增加到i
value 3
。然后在 for 循环完成执行后,setTimeout
回调函数被调用,它i
在其范围内具有相同的值(因为它被提升了)。这就是它打印 3 三次的原因。
推荐阅读
- scala - 当我尝试将 base64 转换为图像时,出现以下错误无法解析重载方法“写入”
- python - 从文本文件中提取数字
- java - 正则表达式 - isMediaFile
- javascript - 刷新页面后如何保留复选框并在会话中保持值
- android - couchbase syncgateway 是否支持使用 access_token 而不是 id_token 登录?
- mongodb - 如何获取不在集合中的元素?
- python - 在Odoo中,在编写控制器时,http和https有什么区别?有一个错误
- mysql - SELECT 语句优化 MySQL
- php - 如何根据从上一页收到的 ID 生成页面(php/sql)
- python - Django admin 自定义降序和升序字段