有人可以解释为什么我在执行此代码时会记录"global value"
吗?
function printFoo() {
console.log(foo);
}
var foo = 'global value';
(function () {
var foo = 'local value';
printFoo();
})();
据我所知,在解析变量时,javascript从最里面的范围开始并向外搜索,那么为什么不在这里打印本地值,如果它在范围链中先前定义的那么?
答案 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具有fooLocalVar
和bar
(以及其他一些东西)的属性。 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';