let declares a block-scoped variable, while var declares a function-scoped variable.
Limiting a variable's scope can help avoid subtle and potentially annoying errors. For example, if you use a let variable inside an if block, it'll only be accessible by code inside the block. If you use var inside an if block, your variable will be visible to the entire function.
I tend to mainly use const, let only when necessary. I never use var and set linter to scream about it at me. IE11 supports it, so unless you develop application for IE compatibility mode (my condolences) I don't see a reason to use var. On the other hand var mainly bites you when declaring closures inside loops, also hoisting is just plain weird.
I find hoisting a convenient feature as I can declare the variable in context to where it's used. It means I do not have to break the flow of how the code reads, making the code easier to understand and less bug prone. Example:
It's only logical that it will be undefined if it's never assigned. With var you can just declare anywhere. While with let it feels like a chore when you have to declare in a parent block, eg. outside the if-block for it to be accessible within another if-block. Lexical function scope works very well in an async language with first class functions, as you deal mostly with functions, which can access it's closures at any time, etc. makes it logical that the function should define the scope, not if-statement or for-loops.