Почему переменная изменяется до выполнения setTimeout в JavaScript?

У меня возникла проблема с асинхронным выполнением кода в JavaScript

Вот пример кода, который показывает суть проблемы:

function display(value) {
   console.log(value);
}

А в другом месте в коде я использую следующее:

var value = 10;
var index = 0;
while (value > 0) {
   setTimeout(function() {display(value);}, 500 * index);
   value--;
   index++;
}

Я ожидал получить вывод 10 9 8 7 6 5 4 3 2 1, но вместо этого вижу 0 0 0 0 0 0 0 0 0 0.

Не понимаю, почему значение переменной изменилось до того, как выполнится функция setTimeout? Как мне исправить этот момент, чтобы получить нужный результат?

Можно также использовать bind — довольно элегантное решение. setTimeout(display.bind(null, value), 500 * index) работает отлично. bind создает новую функцию с фиксированным значением, так что каждый колбэк запоминает свое число. Почему ты используешь while вместо for?

Да, это классическая проблема с областью видимости. С var все колбэки ссылаются на одну переменную, и к моменту выполнения она уже равна 0. Проще всего заменить var на let — тогда каждая итерация получит свое значение. Или можно обернуть в IIFE:

for (var i = 10; i > 0; i--) {
   (function(val) {
       setTimeout(() => display(val), 500 * (10 - val));
   })(i);
}

Это решит проблему.