当我尝试运行此代码段中定义的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.
这不应引发ReferenceError。看起来这不是这里发生的事情。
有人可以解释编译器的实际作用以及如何处理此代码吗?
答案 0 :(得分:2)
在每个函数调用中,引擎都会评估一些序言代码,其中包含形式参数,声明为let
vars,并使用其实际值或默认表达式(如果提供)初始化:
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
),因此无法在初始化之前访问其值。因此是ReferenceError。
请注意,这是一个调用时错误,因此可以进行以下编译:
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页:
对于parameterNames中的每个String paramName,请执行
...执行! envRec.CreateMutableBinding(paramName,false)。
答案 1 :(得分:2)
函数自变量有点像'let'。
在声明之前,我们无法访问使用'let'创建的变量。即,未提升使用'let'创建的变量。
发生这种情况是因为,如果我们在局部范围内声明变量,则它无法访问全局范围变量(除非使用'this') 您的代码可以由此固定-
var b = 3;
function foo( a = 42, b = a + this.b + 5 ) {
// default binding. In this case this.b = global var
}
foo()
如果您这样做,也会看到此错误。
let variable = variable;