Javascript使用动态名称解析吗?

时间:2015-07-30 13:54:27

标签: javascript dynamic late-binding 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()时将动态查找bar a。由于foo的a已经被删除,因此查找将找到全局a,并且bar将打印5.

1 个答案:

答案 0 :(得分:4)

  

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

是。请考虑以下example

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

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

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

  

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

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

此行为实际上是通过提升来解释的,而不是由它无效。即,

  • 正如您所指出的,由于提升,变量a得到已创建(但尚未分配给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()
}

我恰巧在昨晚的答案中提供了对声明赋值 / 初始化之间差异的相当详尽的解释。它解释了这里看到的大部分行为:Declaring vs Initializing a variable?