javascript形参默认值按从左到右顺序逐个初始化,已初始化形参在后续默认值中可访问,未初始化的则不可访问;默认值在调用时求值,位于参数环境记录中,支持外部闭包但不改变线性绑定顺序。

JavaScript 函数执行上下文中的形参默认值,并不是在进入函数时“一次性赋值”,而是在每次求值参数表达式时按顺序执行,且默认值表达式能访问此前已初始化的形参(或外部作用域变量),但不能访问尚未初始化的后续形参——这是由参数初始化的**从左到右、逐个绑定**机制决定的。
形参默认值的求值时机与作用域限制
默认值表达式在函数调用时才求值,而非函数定义时。它位于一个特殊的**参数环境记录(Parameter Environment Record)**中,该环境对已处理的形参可见,对未处理的不可见。
- 形参 a 先被初始化(无论是否有默认值),所以 b 的默认值可以引用 a
- 但 b 尚未初始化时,a 的默认值不能引用 b(会报 ReferenceError)
- 外部变量(如 let x = 10)在默认值中始终可访问,因为外层词法环境链存在
常见错误:试图跨参数引用未初始化的形参
以下代码会抛出 ReferenceError: b is not defined:
function f(a = b, b = 2) { return [a, b]; }
f(); // ❌ 报错
原因:解析 a 的默认值时,b 还没被声明绑定(只在处理 b 参数时才创建绑定),因此无法访问。
正确写法是调整顺序,或改用函数体内部逻辑:
- ✅
function f(b = 2, a = b) { return [a, b]; } - ✅
function f(a, b) { if (a === undefined) a = b ?? 2; if (b === undefined) b = 2; return [a, b]; }
默认值表达式可访问外部闭包,但不构成“参数间依赖”
虽然形参默认值支持闭包访问,但它不改变参数初始化的线性顺序。例如:
let x = 'outer';
function g(a = x, b = () => x) {
x = 'inner';
return [a, b()];
}
g(); // ['outer', 'inner']
这里 a 捕获的是调用时 x 的值('outer'),而 b() 是延迟执行的箭头函数,读取的是执行时的 x('inner')。这说明默认值表达式本身是立即求值的(a = x → 'outer'),但若表达式是函数,则函数体在调用时才运行。
解构参数 + 默认值:嵌套环境更需注意绑定顺序
解构参数的默认值也遵循相同规则,且每个层级独立创建绑定:
function h({ x = y, y = 1 } = {}) { return [x, y]; }
h(); // ❌ ReferenceError: y is not defined
因为对象解构的 x 和 y 是同一层级的属性,默认值表达式中 y 尚未初始化;但下面合法:
- ✅
function h({ y = 1, x = y } = {}) { return [x, y]; } - ✅
function h({ x } = { x: y }, y = 1) { return [x, y]; }(y 在参数列表中先声明)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











