关于oop:OO Javascript:对变量范围的明确解释

关于oop:OO Javascript:对变量范围的明确解释

OO Javascript : Definitive explanation of variable scope

有人可以提供JS中变量范围的解释,因为它适用于对象,函数和闭包?


全局变量

Javascript中的每个变量都是对象的命名属性。例如:-

1
var x = 1;

x被添加到全局对象。全局对象由脚本上下文提供,并且可能已经具有一组属性。例如,在浏览器中,全局对象是窗口。在浏览器中,等同于以上一行的内容是:-

1
window.x = 1;

局部变量

现在,如果我们将其更改为:-

1
2
3
4
function fn()
{
    var x = 1;
}

调用fn时,将创建一个称为执行上下文的新对象,该执行上下文也称为范围(我可以互换使用这些术语)。 x作为属性添加到此范围对象。因此,每次对fn的调用都将获得其自己的范围对象实例,并因此获得其自己的附加到该范围对象的x属性实例。

关闭

现在让我们进一步:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function fnSequence()
{
    var x = 1;
    return function() { return x++; }
}

var fn1 = fnSequence();
var fn2 = fnSequence();

WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn1())
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn2())

注意:在您的上下文中,用对stdout的任何写入替换WScript.Echo

您应该得到的顺序是:-

1 1 2 2 3 4 3 4

那么这里发生了什么?我们有fnSequence,它将变量x初始化为1,并返回一个匿名函数,该函数将返回x的值,然后对其进行递增。

首次执行此函数时,将创建一个范围对象,并将属性x添加到该范围对象,其值为1。匿名函数也在同一执行对象中创建。每个函数对象都有一个scope属性,该属性指向创建它的执行上下文。这将创建称为作用域链的内容,我们将在后面介绍。 fnSequence返回对此函数的引用,并将其存储在fn1中。

请注意,fn1现在指向匿名函数,并且匿名函数具有一个scope属性,该scope属性指向一个仍附加了x属性的范围对象。这称为closure,在该上下文中,为执行创建的功能完成执行后,仍然可以访问执行上下文的内容。

现在,分配给fn2时也会发生相同的序列。 fn2将指向另一个匿名函数,该匿名函数是在第二次调用fnSequence时创建的不同执行上下文中创建的。

范围链

第一次执行fn1保留的功能时会发生什么?为执行匿名函数创建了一个新的执行上下文。从标识符x中可以找到一个返回值。检查该函数的作用域对象的x属性,但没有找到。这就是作用域链的所在。在当前执行上下文中未能找到x的情况下,JavaScript会将函数的scope属性所持有的对象带到那里,并在其中寻找x。由于函数范围是在fnSequence的执行内创建的,因此会找到它,并检索其值并对其进行递增。因此,输出1,并且此范围内的x递增到2。

现在,当执行fn2时,它最终会附加到其x属性仍为1的其他执行上下文中。因此,执行fn2也会得到1。

如您所见,fn1fn2各自生成各自独立的数字序列。


未使用var声明的变量在作用域内是全局的。
函数引入作用域,但请注意,如果块和其他块未引入作用域。

通过Googling Javascript范围,我还可以看到很多有关此的信息。这就是我的建议。
http://www.digital-web.com/articles/scope_in_javascript/


函数引入作用域。 您可以在其他函数中声明函数,从而创建嵌套作用域。 内部范围可以访问外部范围,但是外部范围不能访问内部范围。

使用var关键字将变量绑定到作用域。 所有变量都隐式绑定到顶级范围。 因此,如果省略var关键字,则隐式地引用绑定到顶级的变量。 在浏览器中,顶层是窗口对象。 注意window是它自身的变量,所以window == window.window


推荐阅读