一道面试题告诉了我函数在块级作用域中的提升并没有那么简单

660 阅读4分钟

之前遇到一个面试题,以一个错误的角度解决了,后续有遇到类似的题,发现之前的套路走不通了,所以去研究了一下,并整理了一篇博客,话不多说,直接上题

1. 题目1

{
	function foo() { }
	foo = 1;
}
console.log(foo);

最终的打印结果是:ƒ foo() { } 所以你猜对了吗 [手动狗头]

1.1 题目1 解题思路

{
    console.log(window.foo, foo) // undefined        ƒ foo() { }
    function foo() { }
    console.log(window.foo, foo) // ƒ foo() { }      ƒ foo() { }
    foo = 1;
    console.log(window.foo, foo) // ƒ foo() { }      1
}
console.log(foo);   // ƒ foo() { }

没错,你没看错,就是粗暴的用 console 对此我只想说,没有什么事 console 解决不了, 如果有,那就多写几个 [二次手动狗头]

  • 下边我们来一步一步分析
    • 第一行,打印 undefined ƒ foo() { } 说明此时,函数声明提升到了块级作用域顶部,但没有挂载到全局
    • 第二行,function foo() { } 实际执行时,会有一个隐式操作,将当前 foo 的值,同步给 window
      • 通过 第一行打印结果可以得出,此时 foo 为 ƒ foo() { }
    • 第三行,打印 ƒ foo() { } ƒ foo() { } 说明此时,函数已经被挂载到全局,且在第二行执行了上述的隐式操作
    • 第四行,foo = 1,此时修改的是 块内的 foo,与外部 window 无关
    • 第五行,打印 ƒ foo() { } 1 印证上一行言论
    • 最后一行,打印 ƒ foo() { }

2. 题目2

{
    function foo() { }
    foo = 1;
    function foo() { }
}
console.log(foo);

最终的打印结果是:1 所以你又猜对了吗 [还是手动狗头]

2.1 题目2 解题思路

{
    console.log(window.foo, foo)    // undefined        ƒ foo() { }
    function foo() { }
    console.log(window.foo, foo)    // ƒ foo() { }      ƒ foo() { }
    foo = 1;
    console.log(window.foo, foo)    // ƒ foo() { }      1
    function foo() { }
    console.log(window.foo, foo)    // 1 1
}
console.log(foo);   // 1

没错 console.log YYDS [重复手动狗头]

  • 下边我们来一步一步分析
    • 第一行,打印 undefined ƒ foo() { } 说明此时,函数声明提升到了块级作用域顶部,但没有挂载到全局
    • 第二行,function foo() { } 实际执行时,会有一个隐式操作将当前 foo 的值,同步给 window
      • 通过第一行打印结果可以得出,此时 foo 为 ƒ foo() { }
    • 第三行,打印 ƒ foo() { } ƒ foo() { } 说明此时,函数已经被挂载到全局,且在 第二行执行了上述的隐式操作
    • 第四行,foo = 1,此时修改的是,块内的 foo,与外部 window 无关
    • 第五行,打印 ƒ foo() { } 1 印证上一行言论
    • 第六行,function foo() { } 实际执行时,会有一个·隐式操作·,将当前 foo 的值,同步给 window
      • 通过第五行打印结果可以得出,此时 foo 为 1
    • 第七行,打印 1 1
    • 最后一行,打印 1

3. 题目3

{
    function foo() { }
    foo = 1;
    function foo() { }
    foo = 2;
}
console.log(foo);

最终的打印结果是:1 所以你应该能猜对了吧 [强行手动狗头]

3.1 题目3 解题思路

{
    console.log(window.foo, foo)    // undefined        ƒ foo() { }
    function foo() { }
    console.log(window.foo, foo)    // ƒ foo() { }      ƒ foo() { }
    foo = 1;
    console.log(window.foo, foo)    // ƒ foo() { }      1
    function foo() { }
    console.log(window.foo, foo)    // 1 1
    foo = 2;
    console.log(window.foo, foo)    // 1 2
}
console.log(foo);   // 1

没错,你知道我想说啥 [来个狗头]

  • 下边我们来一步一步分析
    • 第一行,打印 undefined ƒ foo() { } 说明此时,函数声明提升到了块级作用域顶部,但没有挂载到全局
    • 第二行,function foo() { } 实际执行时,会有一个隐式操作将当前 foo 的值,同步给 window
      • 通过第一行打印结果可以得出,此时 foo 为 ƒ foo() { }
    • 第三行,打印 ƒ foo() { } ƒ foo() { } 说明此时,函数已经被挂载到全局,且在 第二行执行了上述的隐式操作
    • 第四行,foo = 1,此时修改的是,块内的 foo,与外部 window 无关
    • 第五行,打印 ƒ foo() { } 1 印证上一行言论
    • 第六行,function foo() { } 实际执行时,会有一个·隐式操作·,将当前 foo 的值,同步给 window
      • 通过第五行行打印结果可以得出,此时 foo 为 1
    • 第七行,打印 1 1
    • 第八行,foo = 2,此时修改的是,块内的 foo,与外部 window 无关
    • 第九行,打印 1 2
    • 最后一行,打印 1

总结

  1. 这里要考验我们的点其实就是 块级作用域中,函数被提升后在执行到声明哪一行时不是什么也没有做,而是在执行完声明后的哪一行代码时,会将当前自身的值同步给外部 window
  2. 这也是最重要的,遇到问题多思考,对于一些看不明白的东西,一定要用 console.log 打印一下,只有对每一个代码代表的意义了解过后才能明白具体的含义是什么
  3. 进步往往是在被打倒后重新站起来的那一刻