Javascript作用域链

Javascript作用域链,javascript,scope,executioncontext,Javascript,Scope,Executioncontext,我读了很多关于javascript作用域链的文章,我认为我对它有相当的了解。然而,一个非常简单的练习让我意识到我还没有完全理解它 我创建了以下代码 function foo () { var b = 2; bar() } function bar () { console.log(b); } foo(); 此代码给出了一个引用错误。但是,我假设它仍然会打印出2。我的理由如下: foo和bar的函数声明 执行Foo时,将创建一个新的执行上下文。Foo的内部属性[[Sco

我读了很多关于javascript作用域链的文章,我认为我对它有相当的了解。然而,一个非常简单的练习让我意识到我还没有完全理解它

我创建了以下代码

function foo () {
  var b = 2;

  bar()

} 

function bar () {
  console.log(b);

}

foo();
此代码给出了一个引用错误。但是,我假设它仍然会打印出2。我的理由如下:

  • foo和bar的函数声明
  • 执行Foo时,将创建一个新的执行上下文。Foo的内部属性[[Scope]设置为全局
  • var b已吊装
  • 变量b被分配为2
  • bar是在foo执行上下文中执行的。因此,我假设bar函数的内部属性[[Scope]]将设置为foo
  • b未在功能栏中定义,因此将查找scopechain并找到值b=2
  • 控制台日志(2)
我的推理是基于我理解函数X的[[Scope]]内部属性设置为在函数X执行时运行的执行上下文。而不是基于函数X的声明位置。

b
是在
foo
的作用域中定义的

bar
是从
foo
的范围调用的,是的,但它是在
foo
的范围之外定义的。这意味着
bar
无法访问
b

图像通常有助于:

将每个红方块视为一个“范围”。
foo
bar
共享外部范围,但它们不能访问彼此的内部范围。

b
foo
的范围中定义

bar
是从
foo
的范围调用的,是的,但它是在
foo
的范围之外定义的。这意味着
bar
无法访问
b

图像通常有助于:


将每个红方块视为一个“范围”。
foo
bar
共享外部范围,但它们不能访问彼此的内部范围。

让我以不同的方式编写代码,以说明范围

var scope = {};
scope.foo = function() {
  var b = 2;   
  scope.bar()   
} 

scope.bar = function() {
// this will look for a property 'b' defined in the bar method, but it doesn's exist
  console.log(b); 
// changing the console.log call to match the changes made above, means it will 
// look like this
  console.log(scope.b)
// but now scope.b is also not defined
}

scope.foo();

换句话说,当您尝试访问“bar”中的“b”时,它将在创建“bar”的范围内搜索它,而不是在调用“bar”的范围内搜索它。

让我以不同的方式编写代码,以说明该范围

var scope = {};
scope.foo = function() {
  var b = 2;   
  scope.bar()   
} 

scope.bar = function() {
// this will look for a property 'b' defined in the bar method, but it doesn's exist
  console.log(b); 
// changing the console.log call to match the changes made above, means it will 
// look like this
  console.log(scope.b)
// but now scope.b is also not defined
}

scope.foo();

换句话说,当您尝试访问“bar”中的“b”时,它将在创建“bar”的范围内搜索它,而不是在调用“bar”的范围内搜索它。

Cerburs感谢您的快速响应。让我困惑的部分是stackoverflow中提出的这个问题。您描述它的方式,在我看来,范围链是由声明函数的执行上下文决定,即其词汇环境,而不是由调用函数的执行上下文决定。然而,链接问题的答案似乎暗示了后者?@JackSpar:我不确定该答案的最后一行是什么意思。没有示例就很难说了。有一件事我确信,
b
是不可访问的,因为它在
foo
的范围内。好的,那我想我理解你了。只是为了确认我的理解。下面的代码不会被认为是一个闭包(程序员通常谈论它的方式)因为函数baz应该已经可以访问函数foo的作用域了,正如它在那里定义/声明的那样?@JackSpar:这是有效的,因为
baz
是在
a
所在的同一作用域中定义的。你也可以从全局作用域公开
baz
,并且仍然让它记录
a
function foo(){var a=2;function baz(){console.log(a);}return baz;}var alias=foo();alias()
完美!非常感谢:)Cerburs感谢您的快速响应。让我困惑的是关于stackoverflow的问题。您描述它的方式,在我看来,作用域链是由声明函数的执行上下文决定的,即它的词法环境,而不是由h调用函数的执行上下文。然而,链接问题的答案似乎暗示了后者?@JackSpar:我不确定该答案中的最后一行是什么意思。没有一个例子就很难说。我确信的一件事是,
b
无法访问,因为它在
foo
的范围内。好的,那我就不知道了hink我理解你。只是为了确认我的理解。下面的代码不会被认为是一个闭包(程序员通常谈论它的方式)因为函数baz应该已经可以访问函数foo的作用域了,正如它在那里定义/声明的那样?@JackSpar:这是有效的,因为
baz
是在
a
所在的同一作用域中定义的。你也可以从全局作用域公开
baz
,并且仍然让它记录
a
function foo(){var a=2;function baz(){console.log(a);}return baz;}var alias=foo();alias();
Perfect!非常感谢:)这确实有助于可视化范围:-)这确实有助于可视化范围:-)