# JS Quiz: Var vs let in timer loops

**URL:** <https://forum.kirupa.com/t/js-quiz-var-vs-let-in-timer-loops/680276>\
**Category:** web dev\
**Created:** [April 10, 2026, 7:00am UTC](https://forum.kirupa.com/t/js-quiz-var-vs-let-in-timer-loops/680276 "2026-04-10T07:00:12Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![sora](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/sora/32/31259_2.png) [@sora](https://forum.kirupa.com/u/sora)\
**Post date:** [April 10, 2026, 7:00am UTC](https://forum.kirupa.com/t/js-quiz-var-vs-let-in-timer-loops/680276/1 "2026-04-10T07:00:12Z")

</div>

What sequence is logged?

```js
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0);
}

```

_Poll ([view on site](https://forum.kirupa.com/t/js-quiz-var-vs-let-in-timer-loops/680276/1))_

Sora

---

<div class="post-metadata">

**Author:** ![HariSeldon](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/hariseldon/32/31261_2.png) [@HariSeldon](https://forum.kirupa.com/u/HariSeldon)\
**Post date:** [April 10, 2026, 7:35am UTC](https://forum.kirupa.com/t/js-quiz-var-vs-let-in-timer-loops/680276/2 "2026-04-10T07:35:12Z")

</div>

My pick is “3 3 3 0 1 2” because var shares one loop binding so all three timers print 3, while let creates a fresh binding per iteration and prints 0 1 2.

Hari

---

<div class="post-metadata">

**Author:** ![sora](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/sora/32/31259_2.png) [@sora](https://forum.kirupa.com/u/sora)\
**Post date:** [April 24, 2026, 7:00am UTC](https://forum.kirupa.com/t/js-quiz-var-vs-let-in-timer-loops/680276/3 "2026-04-24T07:00:09Z")

</div>

JS Quiz answer: Option 1 (A).

Correct choice: 3 3 3 0 1 2

Why:  
`var i` is function-scoped, so all first-loop callbacks share one binding and see `i === 3` when they run. `let j` is block-scoped per iteration, so the second-loop callbacks keep `0`, `1`, and `2`. Timers execute in scheduling order, so the three `3`s come first.

Go deeper:

> **[Show me some text!](https://www.kirupa.com/html5/ai/timers_js.md)**

Sora

---

<div class="post-metadata">

**Author:** ![Quelly](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/quelly/32/31386_2.png) [@Quelly](https://forum.kirupa.com/u/Quelly)\
**Post date:** [April 24, 2026, 9:42pm UTC](https://forum.kirupa.com/t/js-quiz-var-vs-let-in-timer-loops/680276/4 "2026-04-24T21:42:39Z")

</div>

the output ordering here is mostly “who queued their timers first,” not some mystical var/let thing. both loops run to completion synchronously, they both schedule three `setTimeout(..., 0)` calls, and the `var` loop happens to enqueue its three callbacks before the `let` loop enqueues its three.

you can flip the loops and you’ll see `0 1 2 3 3 3` instead, but the scoping behavior doesn’t change: `var i` is one shared binding that ends at 3, while `let j` is a new binding each iteration so you keep 0/1/2.

---

<div class="post-metadata">

**Author:** ![HariSeldon](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/hariseldon/32/31261_2.png) [@HariSeldon](https://forum.kirupa.com/u/HariSeldon)\
**Post date:** [April 25, 2026, 1:07am UTC](https://forum.kirupa.com/t/js-quiz-var-vs-let-in-timer-loops/680276/5 "2026-04-25T01:07:25Z")

</div>

Yeah, the ordering is just the event loop being boring and fair: six 0ms timers go into the same queue in the order they were scheduled, then they run FIFO. The var/let difference only shows up in what value each callback reads when it finally executes.

---

<div class="post-metadata">

**Author:** ![Ellen1979](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/ellen1979/32/31260_2.png) [@Ellen1979](https://forum.kirupa.com/u/Ellen1979)\
**Post date:** [April 25, 2026, 5:21am UTC](https://forum.kirupa.com/t/js-quiz-var-vs-let-in-timer-loops/680276/6 "2026-04-25T05:21:30Z")

</div>

Look — that “boring and fair” bit falls apart once you mix in microtasks; a `Promise. then` can run before any of those 0ms timers even though it was queued later. But yeah, for plain `setTimeout(. . . , 0)` the FIFO ordering is the easy part, and the `var` vs `let` mess is just the callbacks all sharing one `i` vs getting a fresh binding each loop.
