Javascript 是否使用动态名称解析?

Does Javascript Use Dynamic Name Resolution?

这是我要测试的语言是否具有动态名称解析。

function foo() {
    function bar() {
        print a
    }
    var a = 10
    bar()
}

如果语言使用动态名称解析,代码应该打印 10。否则,它应该抛出一个未定义的错误。

Javascript 打印 10。但是 Javascript 使用变量提升,它将 var a 移动到顶部 foo 并使我的测试无效。

编辑: 如果我们可以在JS中删除变量,下面将是一个很好的测试:

var a = 5
function foo() {
    var a = 10
    function bar() {
        print a
    }
    delete a
    bar()
}
foo()

如果 JS 静态解析名称,bar 的 a 引用 foo 的 a。由于 foo 的 a 被删除(如果可能的话),bar 将打印 undefined.

如果JS动态解析名字,bar的a会在调用bar()时动态查找。由于此时 foo 的 a 已被删除,查找将找到全局 a,而 bar 将打印 5。

Does Javascript Use Dynamic Name Resolution?

是的。考虑以下 example

eval("var foo = 'foo';");

console.log(foo);
// > "foo"

变量 foo 直到运行时才绑定到词法环境(由于 eval() 语句),但没有抛出错误(并且代码有效)的事实表明名称是动态解析的。


But Javascript uses variable hoisting, which moves var a to the top foo and invalidates my test.

注意:也许您只是说提升妨碍了您尝试执行的测试?如果是这样,请忽略此答案的其余部分...

这种行为实际上是由 提升解释的,而不是因此而无效的。即,

  • 正如您所指出的,由于提升,变量 a 创建了 (但没有 分配给 , yet) 在 foo() 函数的最顶端。

  • 接下来,你有一个函数声明。碰巧的是,函数声明也被提升到其作用域的顶部。

  • 接下来将值 10 赋值给 a。请注意,这发生在 您实际调用 bar().

  • 之前
  • 最后,您实际上调用了 bar(),此时 a 已经被赋值为 10,导致 0 被打印出来出.

将所有这些结合在一起,您的 foo() 函数的行为就好像它是按如下方式编写的一样:

function foo() {
    // hoisted
    var a;

    // also hoisted
    function bar() {
        // due to hoisting, `a` is lexically in scope here
        console.log(a);
    }

    // the actual assignment
    a = 10

    // the invocation
    bar()
}

我碰巧对 declarationsassignments/initialization[=62] 之间的区别提供了相当详尽的解释=] 在昨晚的回答中。它也解释了此处看到的大部分行为: