OO Javascript:变量范围的确切解释

时间:2008-09-19 05:40:28

标签: javascript oop

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

3 个答案:

答案 0 :(得分:35)

全局变量

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

var x = 1;

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

window.x = 1;

本地变量

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

function fn()
{
    var x = 1;
}

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

封闭

现在让我们进一步: -

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())

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

你应该得到的顺序是: -

1 1 2 2 3 4 3 4

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

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

请注意,fn1现在指向匿名函数,并且匿名函数的范围属性指向仍附加x属性的范围对象。这称为closure,其中执行上下文的内容在为其创建的函数完成执行后仍可访问。

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

范围链

第一次执行fn1所持有的功能时会发生什么?为执行匿名函数创建新的执行上下文。可以从标识符x中找到返回值。检查函数的范围对象是否为x属性,但未找到任何属性。这就是范围链的用武之地。在当前执行上下文中未能找到x JavaScript获取函数的scope属性所持有的对象并在那里查找x。它找到它,因为函数范围是在fnSequence的执行中创建的,检索它的值并递增它。因此输出1并且此范围中的x增加到2.

现在执行fn2时,它最终附加到x属性仍为1的不同执行上下文。因此执行fn2也会导致1。

正如您所看到的,fn1fn2每个都会生成自己独立的数字序列。

答案 1 :(得分:4)

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

我还可以通过Google搜索Javascript范围看到有关此内容的更多信息。这真的是我推荐的。 http://www.digital-web.com/articles/scope_in_javascript/

答案 2 :(得分:1)

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

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