Ant*_*nes 35
Javascript中的每个变量都是对象的命名属性.例如:-
var x = 1;
Run Code Online (Sandbox Code Playgroud)
x被添加到全局对象.全局对象由脚本上下文提供,并且可能已经具有一组属性.例如,在浏览器中,全局对象是窗口.与浏览器中的上述行相同的是: -
window.x = 1;
Run Code Online (Sandbox Code Playgroud)
现在如果我们将其改为: -
function fn()
{
var x = 1;
}
Run Code Online (Sandbox Code Playgroud)
当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())
Run Code Online (Sandbox Code Playgroud)
注意:替换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每个都生成自己独立的数字序列.
| 归档时间: |
|
| 查看次数: |
3373 次 |
| 最近记录: |