Javascript变量范围。这里发生了什么?

时间:2014-09-08 09:31:27

标签: javascript scope

有人可以解释为什么我在执行此代码时会记录"global value"吗?

function printFoo() {
    console.log(foo);
}

var foo = 'global value';

(function () {
    var foo = 'local value';
    printFoo();
})();

据我所知,在解析变量时,javascript从最里面的范围开始并向外搜索,那么为什么不在这里打印本地值,如果它在范围链中先前定义的那么?

3 个答案:

答案 0 :(得分:4)

因为foo中的printFoo是全局的,而不是本地的printFoo。 JavaScript的范围规则是词法的,并且基于创建函数的位置。也就是说,为了说明printFoo的范围是什么,你看看var globalVar; function foo() { var fooLocalVar; return bar; function bar() { var barLocalVar; console.log(globalVar); } } globalVar = "testing"; var b = foo(); 的创建地点(而不是它的使用位置),看看那个地方的范围是什么。

根据规范,变量是技术上对象的属性,特别是规范称为创建变量的执行上下文的变量绑定对象(VBO)。变量绑定对象还引用了包含范围的变量绑定对象,依此类推,直到我们到达全局对象。

例如,请考虑以下代码:

globalVar

如果我们运行该代码,将会有两个VBO:包含foo的全局对象(让我们调用VBO1),以及我们调用foo时创建的执行上下文的VBO(让我们看看)称之为VBO2)。即使bar已经返回,VBO2仍然存在,因为它是在我们调用foo时创建的b函数引用的,我们仍然通过{{{}}引用该函数。 1}}变量。 VBO2具有fooLocalVarbar(以及其他一些东西)的属性。 VBO2也引用了VBO1。

如果我们这样做了:

b();

...然后在调用bar期间,将存在第三个VBO(VBO3),它具有一个名为barLocalVar的属性(以及其他一些东西)和对VBO2的引用。在调用bar期间,当我们执行console.log(globalVar)时,JavaScript引擎会查看VBO3以查看它是否具有名为globalVar的属性。由于它没有,引擎会跟随到下一个外部VBO(VBO2)的链接,并检查是否有globalVar。因为它没有,它会查看VBO1,找到它,并在当时使用其值 。由于bar返回时没有任何内容继续引用VBO3,因此VBO3有资格进行垃圾回收,但请注意,只要我们有b,VBO2就会保留在内存中。

现在让我们进一步说明:

var b2 = foo();

现在我们有一个与调用foo相关的第二个 VBO,因为我们第二次调用foo并保留对某些内容的引用(bar函数,我们记得b2)。这是我们第一次调用foo的VBO,但它具有相同名称的属性,只是不同的值。

VBO在代码中是匿名的(您无法访问实际的VBO本身,只能访问其属性),但有一个例外:全局对象,在全局范围内由this引用,在浏览器上引用有一个属性,window,它用来引用自己。

答案 1 :(得分:1)

  

"我知道在解析变量时,javascript会从   最里面的范围并向外搜索"

这是事实,但是Javascript并没有像你想象的那样嵌套范围。

从另一个函数调用printFoo函数并不意味着printFoo范围在调用函数的范围内。由于printFoo在全局范围内声明,因此函数范围之外的唯一范围是全局范围。

要使范围嵌套,您可以在另一个函数中声明printFoo函数:

var foo = 'global value';

(function () {

    function printFoo() {
        console.log(foo);
    }

    var foo = 'local value';
    printFoo();
})();

现在该函数将在匿名函数中看到本地声明的foo变量,而不是全局范围中的变量。

答案 2 :(得分:0)

因为您正在创建一个全局变量(即window对象的属性)。

即使你在全局变量之前声明的命名函数中调用整个变量,因为函数本身在全局变量声明之后执行,它将打印"global value"

同时检查当前ECMA-Script标准(5.x)是否具有功能范围,但其他块不会创建内部范围。这就是您在函数的本地范围内声明foo但不会影响printFoo foo变量打印的原因。

为什么foo值可用于函数...

// Although this function is declared before
// even "foo" is declared and set, the function is executed
// once "foo" is set.
//
// JavaScript runtime will look for a "foo" variable in the local scope, and
// because it doesn't find it there, it looks in the global scope: bingo!
function printFoo() {
    console.log(foo);
}

var foo = 'global value';