当我尝试运行此代码片段中定义的 foo 函数时,我得到 ReferenceError
自 b is not defined
.
var b = 3;
function foo( a = 42, b = a + b + 5 ) {
// ..
}
foo()
这看起来像 TDZ 错误,因为 b 已在外部作用域中定义,但它尚未在函数签名中用作右侧值。
这是我认为编译器应该做的:
var b;
function foo(..) { .. }
// hoist all functions and variables declarations to the top
// then perform assignments operations
b = 3;
foo();
//create a new execution environment for `foo`
// add `foo` on top of the callstack
// look for variable a, can't find one, hence automatically create a
`var a` in the local execution environment and assign to it the
value `42`
// look for a `var b` in the global execution context, find one, use
the value in it (`3`) as a right-hand-side value.
这不应引发引用错误。看起来这不是这里发生的事情。
有人可以解释一下编译器实际上做了什么以及它如何处理这段代码吗?
最佳答案
在每次函数调用时,引擎都会评估一些序言代码,其中包含形式参数,声明为 let
变量,并使用其实际值或默认表达式(如果提供)进行初始化:
var b = 3;
function foo( ) {
let a = <actual param for a> OR 42;
let b = <actual param for b> OR a + b + 5;
// ..
}
由于函数中的 b
是词法的 (let
),因此在初始化之前不可能访问其值。因此出现了引用错误。
请注意,这是一个调用时错误,因此以下代码可以正常编译:
var b = 1
function foo(b=b) {
console.log(b)
}
实际调用该函数时会发生错误:
var b = 1
function foo(b=b) {
console.log(b)
}
foo()
并且仅当引擎实际计算错误的默认表达式时:
var b = 1
function foo(b=b) {
console.log(b)
}
foo(7)
ECMA标准引用:FunctionDeclarationInstantiation ,第 21 页:
For each String paramName in parameterNames, do
...Perform ! envRec.CreateMutableBinding(paramName, false).
关于javascript - 函数参数未声明变量中的 TDZ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53778917/