【问题标题】:TDZ in undeclared variables of function parameters [duplicate]函数参数的未声明变量中的 TDZ [重复]
【发布时间】:2018-12-31 14:58:09
【问题描述】:

当我尝试运行在这个 sn-p 中定义的 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。看起来这不是这里发生的事情。

有人能解释一下编译器到底做了什么以及它是如何处理这段代码的吗?

【问题讨论】:

    标签: javascript function


    【解决方案1】:

    在每次函数调用时,引擎都会评估一些序言代码,其中包含形式参数,声明为 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 页:

    对于paramNames中的每个String paramName,做

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

    【讨论】:

    • 这非常准确。
    【解决方案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;
    

    【讨论】:

    • "g 在我们尝试使用 'let' 创建同名变量时未声明。" 这不太正确。它实际上是声明的,但声明未初始化,导致错误。 var 声明 OTOH 始终使用 undefined 初始化。
    • 是的,你是对的。
    猜你喜欢
    • 2018-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-30
    相关资源
    最近更新 更多