有人可以在JS中提供变量范围的解释,因为它适用于对象,函数和闭包吗?
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
现在指向匿名函数,并且匿名函数的scope属性指向仍x
附加属性的范围对象.这被称为closure
执行上下文的内容在为其创建的函数完成执行后仍可访问的位置.
现在,在分配时会发生相同的序列fn2
. fn2
将指向一个不同的匿名函数,该函数是在fnSequence
第二次调用时创建的不同执行上下文中创建的.
当fn1
第一次执行所持有的功能时会发生什么?为执行匿名函数创建新的执行上下文.可以从标识符中找到返回值x
.检查函数的范围对象是否有x
属性,但未找到任何属性.这是范围链的来源.在x
当前执行上下文中找不到JavaScript,它获取函数的scope属性所持有的对象并在x
那里查找.它找到它,因为函数范围是在执行中创建的fnSequence
,检索它的值并递增它.因此输出1并且x
在此范围内递增到2.
现在fn2
执行时,它最终附加到其x
属性仍为1 的不同执行上下文.因此执行fn2
也会导致1.
如您所见fn1
,fn2
每个都生成自己独立的数字序列.