函数声明和函数表达式的作用域链结构完全一致,均按定义位置建立静态词法作用域链并支持闭包;区别仅在于提升行为——函数声明被整体提升并初始化,可提前调用;函数表达式仅变量名可能提升(var)或受tdz限制(let/const),函数体及[[environment]]在执行赋值时才创建。

函数声明和函数表达式在作用域链上的表现完全一致——它们都遵循相同的词法作用域规则,查找变量时都严格依赖定义时的位置所确定的作用域链。区别不在链本身,而在于**如何进入作用域链、何时被纳入链中,以及是否参与变量提升**。
作用域链的起点由定义位置决定,与声明方式无关
无论是 function foo() {} 还是 const foo = function() {},只要函数是在某个嵌套层级中定义的,它内部的 [[Environment]] 就会指向该位置的词法环境。这意味着:
- 两者都能正常形成闭包,访问外层变量
- 两者在调用时都沿同一条静态路径向上查找变量(从自身 → 外层函数 → 全局)
- 即使把函数表达式传到另一个模块执行,它仍按原定义位置找变量,不随调用位置改变
关键差异体现在“能否被提前访问”,而非作用域链结构
函数声明会被提升到作用域顶部,因此在代码执行前就已绑定到当前词法环境;函数表达式只是变量赋值,其函数体直到执行到赋值语句才创建并关联 [[Environment]]。这导致:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 函数声明:定义前就能调用,且此时它的作用域链已就绪
- 函数表达式:定义前调用会报错(
TypeError: xxx is not a function),因为变量虽存在但值为undefined,根本没生成函数对象,更谈不上建立作用域链 - 箭头函数属于函数表达式语法糖,同样不提升,
[[Environment]]继承外层函数,但没有自己的this和arguments
块级作用域中行为一致,但可声明位置不同
两者都尊重 let/const 的块级作用域规则,但语法限制不同:
- 函数声明在
if或for块内属于非标准行为,部分引擎会提升到外层,行为不可靠 - 函数表达式可安全写在任意块内:
if (ok) { const handler = function() { console.log(x); }; },其中x的查找仍走定义时的外层作用域链 - 块内用
let或const声明的函数表达式,其变量本身只在该块内有效,但函数内部的作用域链不受影响
TDZ 和 var 提升不影响作用域链逻辑,只影响访问时机
无论声明还是表达式,只要用了 let/const,其绑定就在块开头进入暂时性死区(TDZ);var 声明的函数表达式变量会被提升但值为 undefined。但注意:
- 作用域链查找过程不变:仍是“先查当前环境,找不到再往上”
- TDZ 不是打断链,而是阻止访问——未声明前读取直接报错,不会继续向上找
-
var fn = function() {}中,fn变量名被提升,但函数对象尚未创建,所以链还没建立;等执行到赋值语句,函数对象诞生,[[Environment]]才被设置
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










