当前位置:网站首页>In depth analysis of for (VaR I = 0; I < 5; i++) {settimeout (() => console.log (I), 1000)}
In depth analysis of for (VaR I = 0; I < 5; i++) {settimeout (() => console.log (I), 1000)}
2022-07-05 06:08:00 【weixin_ forty-one million three hundred and eighty-seven thousa】
A common question
for(var i = 0;i < 5;i++)
{
setTimeout(() => console.log(i),1000);
}
For this question , I'm sure you've heard about it , The final output is
5 5 5 5 5
without doubt , This is inconsistent with our expected output ( The expected output is 0 1 2 3 4). The reason for this problem , Namely var The scope of the identifier declared by the keyword is the function scope .
So in the above js In the code ,i Identifiers are stored in the global scope . therefore , When setTimeout When the callback function of ,i The value stored in the identifier is 5 了 (5 It is the end of the cycle ), So... Will be output 5 individual 5.
But here is another doubtful point , Why? setTimeout When it comes to execution i It's already 5 了 , Because I waited 1 Seconds ?
setTimeout Execution time of
Now we know the answer to the first question and the reason for the mistake , What about the following question
for(var i = 0;i < 5;i++)
{
setTimeout(() => console.log(i),0);
}
In fact, the output of this problem is also
5 5 5 5 5
This output actually tells us the answer to our doubts just now , Not because of waiting 1 Seconds cause setTimeout When it comes to execution i The value stored in becomes 5.
So what's the reason ?
We can read this code carefully , We found that for A loop is a synchronization code , and setTimeout It's asynchronous code .
So that's it , We immediately associate the cycle of events , Event loops can help us distinguish the execution timing of synchronous code and asynchronous code . The event loop is simply to execute the macro task first , Then empty a cycle of the micro task queue .
The common macro tasks are
- <script> All synchronization codes under the tag
- setTimeout、setInterval
- I/O
- UI Interaction
Common micro tasks are
- Promise Related methods
therefore js The engine is doing this for In the cycle , Yes setTimeout, Will be setTimeout Put in the macro task queue , Then execute the synchronization code , When the synchronization code is executed, check the micro task queue , Only when the next round of event cycle begins setTimeout Remove... From the macro task queue .
therefore ,setTimeout The execution of must be in all synchronous code , That is the whole for After the execution of the loop , So in setTimeout When it comes to execution ,i It's already 5 了 .
resolvent
Now we have made clear the reason why the code output does not match the expectation , That's the scope .
First of all, it's easy to think of , If the identifier i Limited to block scope , You can solve the problem .
Use let
for(let i = 0;i < 5;i++)
{
setTimeout(() => console.log(i),1000);
}
setTimeout Callback function for () => console.log(i) The lexical scope of is for Block scope inside the loop . This function is specified as a callback function , without doubt , Will be called outside its lexical scope , And when it is called js The engine will be right i Conduct RHS quote , So even if for The loop has been executed , The scope of each layer of the loop is still () => console.log(i) maintain , therefore setTimeout When executing, you can access the loop of each layer i. This actually forms what we often call closures ( A function is called outside its defined lexical scope , And maintain the reference to the variables in the lexical scope it is defined ).
Use IIFE
IIFE yes Immediately Invoked Function Expression, Call function expression now .
for(var i = 0;i < 5;i++)
{
setTimeout((function(i){
return () => console.log(i);
})(i),1000)
}
Use here IIFE The purpose of is to use closures . Each layer circulates IIFE It is equivalent to creating a function scope for each layer of loop , And put each layer of circulation i The value of is passed in as a parameter , Store in IIFE In the identifier with the same name of the function scope of . And this IIFE take () => console.log(i) Returned as a value to setTimeout.
alike ,() => console.log(i) Is defined in IIFE Function scope of , It will be called outside its lexical scope , And in () => console.log(i) Maintain references to variables in its lexical scope ( ad locum , In fact, in the scope chain search of lexical scope ‘ Homonymous masking ‘ It also worked ).() => console.log(i) Function is called ,js The engine will be right i Conduct RHS lookup ,js The engine first asked () => console.log(i) The scope of its own function , No such identifier found , Then search rules according to lexical scope , Go to () => console.log(i) The upper lexical scope of , That is to say IIFE Function scope lookup identifier i, ad locum js The engine found the identifier i, So this closure exists ( Yes IIFE A reference to a scope ),setTimeout When executing, you can access the loop of each layer i.
边栏推荐
- 1.13 - RISC/CISC
- Data visualization chart summary (II)
- 实时时钟 (RTC)
- Overview of variable resistors - structure, operation and different applications
- Matrixdb V4.5.0 was launched with a new mars2 storage engine!
- [jailhouse article] look mum, no VM exits
- Annotation and reflection
- leetcode-6110:网格图中递增路径的数目
- The connection and solution between the shortest Hamilton path and the traveling salesman problem
- leetcode-22:括号生成
猜你喜欢
Navicat連接Oracle數據庫報錯ORA-28547或ORA-03135
【云原生】微服务之Feign自定义配置的记录
How to adjust bugs in general projects ----- take you through the whole process by hand
个人开发的渗透测试工具Satania v1.2更新
Data visualization chart summary (I)
【Jailhouse 文章】Performance measurements for hypervisors on embedded ARM processors
MIT-6874-Deep Learning in the Life Sciences Week 7
1.13 - RISC/CISC
[practical skills] how to do a good job in technical training?
LeetCode 0107.二叉树的层序遍历II - 另一种方法
随机推荐
可变电阻器概述——结构、工作和不同应用
AtCoder Grand Contest 013 E - Placing Squares
R language [import and export of dataset]
1.14 - 流水线
RGB LED infinite mirror controlled by Arduino
Fried chicken nuggets and fifa22
[practical skills] how to do a good job in technical training?
[cloud native] record of feign custom configuration of microservices
Implement a fixed capacity stack
【Rust 笔记】17-并发(上)
The difference between CPU core and logical processor
Binary search template
【云原生】微服务之Feign自定义配置的记录
LeetCode 1200.最小绝对差
【Rust 笔记】16-输入与输出(上)
[jailhouse article] jailhouse hypervisor
QT判断界面当前点击的按钮和当前鼠标坐标
redis发布订阅命令行实现
开源存储这么香,为何我们还要坚持自研?
CCPC Weihai 2021m eight hundred and ten thousand nine hundred and seventy-five