I think this was discussed there: https://news.ycombinator.com/item?id=8933979
The reason is that 'let' gives 'i' 'block scope', meaning that each iteration of the loop block gets its own scope so that 'i' isn't overwritten each time, and each function you declare captures the value of 'i' at the time it was declared.
In other words - the way you originally expected 'var' to behave is how 'let' behaves!