0

Here is a script:

for(var i = 0; i < 5; i++) {
  setTimeout(function() { console.log(i); }, 0);
};

Theoretically it should output just five "5" in console. But when we executing it in Chrome, Opera or Safari console, there are some strange numbers aside result. OS is macOS Sierra 10.12.1.

E.g.

Chrome 54.0.2840.98 (64-bit):

for(var i = 0; i < 5; i++) {
      setTimeout(function() { console.log(i); }, 0);
    };
2105
⑤ 5

Safari 10.0.1:

> for(var i = 0; i < 5; i++) {
      setTimeout(function() { console.log(i); }, 0);
    };
< 6
> for(var i = 0; i < 5; i++) {
      setTimeout(function() { console.log(i); }, 0);
    };
< 11
> for(var i = 0; i < 5; i++) {
      setTimeout(function() { console.log(i); }, 0);
    };
< 16

Opera 39.0:

for(var i = 0; i < 5; i++) {
      setTimeout(function() { console.log(i); }, 0);
    };
5
⑤ 5                                    VM73:2
for(var i = 0; i < 5; i++) {
      setTimeout(function() { console.log(i); }, 0);
    };
10
⑤ 5                                    VM74:2

You could try it yourself. What is interesting - same code included in HTML page works as it should. Depending on tab for which console is opened numbers are different. What is it? Guess it some kind of internal counter for cycles but not sure. Another thought - console shows what executing function return value. Perhaps it is. But for does not return anything. At least it should not. Same code but without setTimeout shows undefined instead of strange numbers as it should works. Maybe somebody know about it a bit more than me and internet. Any thoughts are highly appreciated. Sorry for my English. Thank you!

Serj.by
  • 534
  • 5
  • 17
  • Use `let` instead of `var` to limit the variable in the same scope – Endless Dec 03 '16 at 11:18
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Endless Dec 03 '16 at 11:19
  • In the Chrome and Opera examples, the 2105 is the final timer resulting from the `setTimeout` call. `⑤ 5` means that the number `5` has been output five times, obviously. Safari seems to be printing the timer ID as well, although I have no idea why it is not outputting `i`, possibly a console settings issue. –  Dec 03 '16 at 13:02
  • I have no concern about `⑤ 5`, main question is about strange numbers in "results" of `for` function. – Serj.by Dec 03 '16 at 17:05
  • @Endless, at least in Chrome it doesn't matter. – Serj.by Dec 03 '16 at 17:08

2 Answers2

2

Here's the minimal example:

for(var i = 0; i < 5; i++) setTimeout(function() {})
> 71 (or whatever)

Although statements don't have a value, the console tries to be "helpful" and outputs what the last evaluated expression returned - in this case it's setTimeout(...) which returns the timeout ID - some arbitrary number.

georg
  • 211,518
  • 52
  • 313
  • 390
  • You maybe right but... Just try to execute this code sequentially. It will gives you (in my case) 75, 80, 85, 90, 95, 100 etc... So basically it increases by 5 (cycle iterations number), that's why it is interesting what is this number? – Serj.by Dec 03 '16 at 16:42
  • @Serj.by: timeout IDs appear to be allocated sequentially, so yes, your code allocates 5 timeouts and returns the last ID. Edited "random" to "arbitrary" to avoid confusion ;) – georg Dec 03 '16 at 17:14
1

It is probably printing the return value from setTimeout. It can be used to clear it using clearTimeout. If you run that again you will get another value as each timeout should have its own unique number to stop it.

Meanwhile, you probably have filtered console to show only errors change it it show all to see the actual logs as well. DevTools have only errors by default now I guess. (Safari)

sabithpocker
  • 15,274
  • 1
  • 42
  • 75
  • Thanks for an answer! `clearTimeout` however will destroy timeout immediately, though it need some time for execution, so nothing will be executed. `for (var i=0; i < 5; i++) { var to = setTimeout(function () { console.log(i); }, 0); clearTimeout (to); } undefined` Perhaps you mentioned something else? But clearing timeout gives predictable undefined result. Anyhow, it isn't executing code inside setTimeout. – Serj.by Dec 03 '16 at 16:36
  • I just said that the returned number is used as a unique ID to clearTimeout. The reason why setTimeout is returning a unique ID. – sabithpocker Dec 05 '16 at 07:27
  • Oh, ok, got it. Sorry, missunderstood you. Seems like it is really working this way. – Serj.by Dec 06 '16 at 10:44