我的分析和笔记如下

function Foo() {
    getName = function () { // 注意:这里还没定义window.getName
        console.log(1);
    };
    return this;
}
Foo.getName = function () {
    console.log(2);
};
Foo.prototype.getName = function () {
    console.log(3);
};
var getName = function () { // 第一次有效赋值window.getName 注意!!!!var定义的和不定义直接用的变量都是window的属性!而let定义的则不是window的属性!!!
    console.log(4);
};
function getName() {    // 同名的:函数会被变量赋值覆盖「函数提升优先级高于变量提升,且不会被变量声明覆盖,但是会被变量赋值覆盖」
    console.log(5);
}
Foo.getName();          // 2 第7行定义了Foo的属性 注意!仅限于Foo这个构造函数!它产生的实例对象不含该属性!!!
getName();              // 4 第13行的输出
Foo().getName();        // 1 第二次有效赋值window.getName
getName();              // 1 上一行执行Foo()函数时,第2行代码重新赋值了window.getName
new Foo.getName();      // 2 调用了构造函数,函数内容是第8行的一条语句
new getName();          // 1 调用了构造函数,函数内容是第3行的一条语句(自加)
new Foo().getName();    // 3 因为new后面带参数列表「e.g. new func()而不是new func」的优先级高于成员运算符「.」的优先级,所以这里等价于 (new Foo()).getName(), 先new一个Foo的实例,再执行这个实例的getName方法,但是这个实例本身没有这个方法「第7行定义了Foo的属性 注意!仅限于Foo这个构造函数!它产生的实例对象不含该属性!!!」,所以去原型链__protot__上边找,实例.__protot__ === Foo.prototype,所以输出 3。
new new Foo().getName();// 3 解析:执行顺序:1、a = new Foo();2、b = a.getName; 3、new b(); 第一步得到一个实例,this指向新建的对象; 第二步得到实例对象原型上的getName方法,但是它内部没有提供任何构造器属性; 第三步所以new这个方法只能得到一个空属性的实例

// 2411233

/*
补充:

关于上述 5中 new Foo.getName()先执行 Foo.getName(),而6中 new Foo().getName() 先执行 new Foo(),是因为:

new Foo() 属于new(带参数列表)
new Foo属于new(无参数列表)
无参数列表的优先级为18,而成员访问的优先级为19,高于无参数列表。因此new Foo.getName()先执行Foo.getName()

带参数列表的优先级为19,而成员访问的优先级也为19,按照运算符规则(同一优先级,按照从左向右的执行顺序),new Foo().getName()先执行new Foo(),再对new之后的实例进行成员访问.getName()操作。
这是js运算符的优先级链接,可查看每个运算符的优先级。
*/

A Student on the way to full stack of Web3.