首页 > 解决方案 > 函数参数未声明变量中的 TDZ

问题描述

当我尝试运行此代码段中定义的 foo 函数时,我得到一个ReferenceErrorsince 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。看起来这不是这里发生的事情。

有人可以解释编译器实际上做了什么以及它如何处理这段代码吗?

标签: javascriptfunction

解决方案


在每个函数调用中,引擎都会评估一些序言代码,其中包含形式参数,声明为letvars 并使用它们的实际值或默认表达式进行初始化,如果提供的话:

var b = 3;

function foo( ) {
    let a = <actual param for a> OR 42;
    let b = <actual param for b> OR a + b + 5;
   // ..
}

由于bin 函数是词法 ( 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 页:

对于 parameterNames 中的每个 String paramName,执行

...履行 !envRec.CreateMutableBinding(paramName, false)。


推荐阅读