You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中函数与块级作用域相关的JS异常行为解析

两段JavaScript代码的执行结果差异解析

代码段1

{
    function f() {return 1}
    f = function() {return 2}
    function f() {return 3}
}
console.log(f()); // 输出2

代码段2

{
    function f() {return 1}
    f = function() {return 2}
}
console.log(f()); // 输出1

你的分析与疑问

你对代码段1的执行逻辑理解基本正确,但代码段2的结果超出预期——你认为应该输出2,实际却输出1,疑惑赋值语句f = function() {return 2}没有修改全局的f。

核心原因:非严格模式下块级函数的特殊行为

这是因为在**非严格模式(sloppy mode)**中,块级函数声明的行为有特殊规则,关键在于两点:

  1. 块内的函数声明会在全局/包含块的外层作用域创建一个同名变量,初始值为undefined。
  2. 当代码执行到块内的函数声明语句时,会将当前块内的函数绑定值同步到外层作用域的同名变量中。

代码段2的详细执行流程

  1. 编译阶段:
    • 全局作用域创建变量f,初始值为undefined。
    • 块级作用域内提升函数function f() {return 1},块内的f绑定初始指向这个函数。
  2. 执行阶段:
    • 进入块后,执行第一个函数声明function f() {return 1}:将块内f的值(return1的函数)同步到全局的f,此时全局f变为return1的函数。
    • 执行赋值语句f = function() {return 2}:这里修改的是块内的f绑定,块内的f现在指向return2的函数,但全局的f没有被同步更新(因为没有后续的函数声明触发同步)。
    • 退出块后,块内的f绑定销毁,全局的f仍然保持return1的函数。
    • 最终调用f()时,执行的是全局的函数,输出1。

代码段1的详细执行流程

  1. 编译阶段:
    • 全局作用域创建变量f,初始值为undefined。
    • 块级作用域内提升两个函数声明,最后一个function f() {return 3}覆盖前面的,块内的f初始指向return3的函数。
  2. 执行阶段:
    • 进入块后,执行第一个函数声明function f() {return 1}:将块内f的值改为return1的函数,并同步到全局,此时全局f是return1的函数。
    • 执行赋值语句f = function() {return 2}:修改块内的f为return2的函数,全局f暂时还是return1。
    • 执行第二个函数声明function f() {return 3}:此时会将**当前块内f的最新值(return2的函数)**同步到全局的f,全局f变为return2的函数。
    • 退出块后,全局的f保持return2的函数,调用f()输出2。

总结

非严格模式下,块内的函数声明语句是同步块内绑定到外层作用域的触发点。代码段1因为有最后一个函数声明,把赋值后的块内f同步到了全局;而代码段2没有后续的函数声明,赋值只修改了块内的临时绑定,全局f停留在第一次同步的值。

内容的提问来源于stack exchange,提问作者pdlaf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 00:16:13