首页 > 解决方案 > 关于 Javascript 执行上下文的说明

问题描述

我一直在努力巩固我对 JS 执行上下文的理解,并且无法解释为什么下面的代码没有打印出“hello world”。

var foo = "foo";

function test1() {
    console.log(foo)
    var bar = "hello world";
    test2();
}

function test2() {
    console.log(bar);
}

test1();

我(诚然非常不稳定)的理解是test2(),在 内部执行test1(),可以访问test1()的执行上下文,并且应该能够bar通过将作用域链向上移动到定义test1()的执行上下文来解析变量名称bar。相反,我在尝试打印时收到参考错误bar

由于 JS 的词法作用域,我可以理解下面的代码是如何工作的,但我希望能解释一下 JS 如何在执行上下文和作用域链方面以不同的方式解释它们。

function test1() {
    console.log(foo)
    var bar = "hello world";
    function test2() {
        console.log(bar);
    }
    test2();
}

test1();

到目前为止,我自己寻找解释的最佳尝试是修改第一个代码块,如下所示:

var foo = "foo";
var bar = "not hello world :("

function test1() {
    console.log(foo)
    var bar = "hello world";
    test2();
}

function test2() {
    console.log(bar);
}

test1();

在这里,调用test2()打印出在全局范围内定义的“not hello world :(”。我的第一个想法是,test2()将范围链向上移动到test1的执行上下文,到全局执行上下文,但这似乎不对, 因为它会在到达全局定义之前找到barinside of的定义. 因此, 我的第二个猜测是, 的定义是在定义全局执行上下文时创建一个类似“闭包”的捕获, 并在内部调用它产生一个null/undefined 的值,因为那是它在函数定义时的值(根本没有要提升的声明)。因此,它不会向上移动到的执行上下文来搜索标识符。test1()test2()test1()bartest1()

任何解释/资源都会非常有帮助。我显然对这门语言很陌生,所以如果我的词汇/术语不太正确,请道歉。在此先感谢您的帮助。

标签: javascriptclosuresexecutioncontext

解决方案


从哪里调用它,调用者的范围无关紧要。解析局部变量重要的是它的声明位置。

test2()无法访问,因为在声明函数时该范围内bar没有命名变量。bar事后无法操纵该本地范围。它是一成不变的。

这意味着一个函数可以访问本地范围内的变量,或者任何包含该函数声明的范围内的变量。这意味着跟随{}包含该函数声明的大括号对一直回到文件的根目录。把它想象成一棵树:你的函数可以访问该函数和树根之间的任何变量。它将无法访问该树的其他分支。


这是一件非常好的事情。它强制执行良好的封装。从调用者的角度来看,您希望您的函数是一个黑匣子。您希望函数中的局部变量是真正的局部变量。并且您想知道在编写函数时函数可以访问哪些变量,而不是对运行函数时弹出的值感到惊讶。


推荐阅读