JavaScript函数默认参数作用域及变量声明相关技术疑问
函数参数作用域与声明规则详解
ECMAScript规范中,函数声明实例化的逻辑明确:若函数存在默认参数初始化器,会为函数体声明创建第二个环境记录——默认参数会形成独立的作用域,示例代码如下:
function sum(a = 1, b = () => a) { return a + b() }
问题1:函数的参数是以var声明、let声明的方式初始化,还是两者都不是?
函数参数的初始化规则既不属于var也不属于let,是一套独立的声明逻辑:
- 和
let/const类似,参数声明存在暂时性死区(TDZ),在参数初始化完成前访问参数会抛出错误; - 不同于
var,参数不会被提升到函数作用域的最顶部; - 当存在默认参数时,参数拥有独立于函数体的专属作用域,这是
var/let都不具备的特性。
问题2:为何第二个代码片段中const c = 3处于块级作用域,而第一个代码片段中它仅处于预期的局部作用域?
第一个无默认参数的代码片段:
function sum(a, b) { debugger const c = 3 return a + b }
此时函数参数与函数体共享同一个函数环境记录,没有额外的作用域分层,const c直接属于函数的局部作用域。
第二个带默认参数的代码片段:
function sum(a = 1, b = 2) { debugger const c = 3 return a + b }
因为存在默认参数,规范会创建两个环境记录:一个是承载参数声明与默认值逻辑的参数环境记录,另一个是承载函数体内声明的函数体环境记录。函数体作用域相当于嵌套在参数作用域内部的块级作用域,因此调试器中会显示const c处于块级作用域中。
问题3:既然会创建新作用域,为何第一个代码片段中可以存在两个var a变量,而第二个代码片段中编译器会报错提示重声明?
第一个含var声明的代码片段:
function sum(a = 1, b = 2) { debugger var a = 3 return a + b }
var声明的变量会被提升到所在函数作用域的顶部,且允许在同一作用域内重复声明。即便参数与函数体分属嵌套作用域,var a的声明会直接作用于整个函数作用域,本质是对参数a的重新赋值,而非创建新变量,因此不会报错。
第二个含const声明的代码片段:
function sum(a = 1, b = 2) { debugger const a = 3 return a + b }
const/let属于块级声明,会在当前函数体作用域创建新的绑定。由于参数作用域的a会被遮蔽到函数体作用域中,const a相当于在同一作用域内尝试重复声明同名变量,而const严格禁止同一作用域内的重复声明,因此编译器会抛出错误。
内容的提问来源于stack exchange,提问作者dbzx10299
相关产品推荐
相关产品推荐

