简体   繁体   中英

Does Javascript Use Dynamic Name Resolution?

This is my go to test for whether a language has dynamic name resolution.

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

If the language uses dynamic name resolution, the code should print 10. Otherwise, it should throw an undefined error.

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

Edit: If we could delete variables in JS, the following would be an excellent test:

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

If JS statically resolves names, bar's a references foo's a . Since foo's a gets deleted (if it were possible), bar would print undefined .

If JS dynamically resolves names, bar's a will be looked up dynamically when bar() is called. Since foo's a is already deleted at this point, the lookup would find the global a, and bar would print 5.

Does Javascript Use Dynamic Name Resolution?

Yes. Consider the following example :

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

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

The variable foo isn't bound to the lexical environment until runtime (due to the eval() statement), but the fact that no error is thrown (and the code works) demonstrates that the name is resolved dynamically.


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

Note: maybe you're just saying that hoisting is getting in the way of the test you're trying to perform? If so, please ignore the rest of this answer...

This behavior is actually explained by hoisting, rather than invalidated by it. Ie,

  • As you pointed out, due to hoisting, the variable a gets created (but not assigned to , yet) at the very top of the foo() function.

  • Next, you have a function declaration. As it happens, function declarations get hoisted to the top of their scope, too.

  • Next you assign the value 10 to a . Note that this happens before you actually invoke bar() .

  • Finally, you actually invoke bar() , at which point a already has been assigned the value 10 , resulting in 0 being printed out.

Combining that all together, your foo() function behaves the same as if it had been written as follows:

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()
}

I happened to provide a fairly thorough explanation of the difference between declarations and assignments / initialization in an answer just last night. It explains much of the behavior seen here as well: Declaring vs Initializing a variable?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM