Как работают циклы с таймаутом?
Первое что нужно понять, таймер работает асинхронно, а значит будет выполнен после цикла.
Второе - let имеет блочную область видимости (переменная видна в том блоке, где была объявлена, при этом первый операнд for считается тем же блоком, что и тело цикла)
Третье - циклы создают новый скоуп на каждую итерацию (на каждой итерации будет свой let i, при условии что этот оператор внутри цикла)

Ну и еще, в Ваших примерах 1000 относится не к таймауту, это просто бесполезная операция, а таймаут получит значение по умолчанию - 0, думаю это не совсем то, что Вы ожидаете.

Еще один важный момент, функциональное выражение (а стрелочная функция - это тоже функциональное выражение) внутри цикла будет создавать по функции на каждой итерации цикла. Это очень плохо и по памяти и по производительности (такие функции еще и компилироваться и оптимизироваться будут раздельно). И если в случае с let внутри цикла функции хотя бы будут отличаться замыканием (каждая замкнет свою i), то в первом случае будет 5 абсолютно идентичных функций.
Тут можно очень хорошо показать себя, если помимо объяснения принципов работы вспомнить, что setTimeout умеет передавать аргументы в свой колбэк:const f = i => {
  console.log(i);
};
for (let i = 0; i < 5; i++) {
  setTimeout(f, 1000, i);
}
в первом случае у тебя одна глобальная переменная i.
повещенные 5 таймеров сработают через секунду и все выведут ее текущее значение.

во втором случае переменных i две. параметр цикла и глобальная.
но тут еще лямбда замыкание.  
Я редко пишу на явоскрипт. В других языках проблему решают по разному.
например специальный модификатор final . А гдето как в вашем случае 
создается неявная копия переменной, которая уже используется в отложенном событии