Why the result of the first function execution is undefined ?
Because you don't bind this to anything in the function call (you neither have objectThatWillBecomeThis.printName() nor printName.call(objectThatWillBecomeThis)). In strict mode, this would crash because this would be undefined then and you'd try to read undefined.myName. But since you didn't enable strict mode, the legacy behavior is active in which this - when not explicitly set - will be set to the global object. However, the global object doesn't have any property myName (in the browser: there is no window.myName) so the result is undefined.
why output 'outer' after changing let to var ?
Because if you run this code in the global scope, var outside of any other scope will create a property on the global object (window.myName). let doesn't do that:
At the top level of programs and functions, let, unlike var, does not create a property on the global object. For example:
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
If you'd move the code inside a function, it wouldn't work either, by the way, because the var (or let, doesn't matter now) statement would just create a local variable in the function and not a property on the global object, so there would be no way to access it through any object's myName property.