分享

JavaScript作用域链其二:函数的生命周期

 sofes 2014-08-11

函数的的生命周期分为创建和激活阶段(调用时),让我们详细研究它。

函数创建

众所周知,在进入上下文时函数声明放到变量/活动(VO/AO)对象中。让我们看看在全局上下文中的变量和函数声明(这里变量对象是全局对象自身,我们还记得,是吧?)

1var x = 10;
2  
3function foo() {
4  var y = 20;
5  alert(x + y);
6}
7  
8foo(); // 30

在函数激活时,我们得到正确的(预期的)结果--30。但是,有一个很重要的特点。

此前,我们仅仅谈到有关当前上下文的变量对象。这里,我们看到变量“y”在函数“foo”中定义(意味着它在foo上下文的AO中),但是变量“x”并未在“foo”上下文中定义,相应地,它也不会添加到“foo”的AO中。乍一看,变量“x”相对于函数“foo”根本就不存在;但正如我们在下面看到的——也仅仅是“一瞥”,我们发现,“foo”上下文的活动对象中仅包含一个属性--“y”。

1fooContext.AO = {
2  y: undefined // undefined – 进入上下文的时候是20 – at activation
3};

函数“foo”如何访问到变量“x”?理论上函数应该能访问一个更高一层上下文的变量对象。实际上它正是这样,这种机制是通过函数内部的[[scope]]属性来实现的。

[[scope]]是所有父变量对象的层级链,处于当前函数上下文之上,在函数创建时存于其中。

注意这重要的一点--[[scope]]在函数创建时被存储--静态(不变的),永远永远,直至函数销毁。即:函数可以永不调用,但[[scope]]属性已经写入,并存储在函数对象中。

另外一个需要考虑的是--与作用域链对比,[[scope]]是函数的一个属性而不是上下文。考虑到上面的例子,函数“foo”的[[scope]]如下:

1foo.[[Scope]] = [
2  globalContext.VO // === Global
3];

举例来说,我们用通常的ECMAScript 数组展现作用域和[[scope]]。

继续,我们知道在函数调用时进入上下文,这时候活动对象被创建,this和作用域(作用域链)被确定。让我们详细考虑这一时刻。

函数激活

正如在定义中说到的,进入上下文创建AO/VO之后,上下文的Scope属性(变量查找的一个作用域链)作如下定义:

1Scope = AO|VO + [[Scope]]

上面代码的意思是:活动对象是作用域数组的第一个对象,即添加到作用域的前端。

1Scope = [AO].concat([[Scope]]);

这个特点对于标示符解析的处理来说很重要。标示符解析是一个处理过程,用来确定一个变量(或函数声明)属于哪个变量对象。

这个算法的返回值中,我们总有一个引用类型,它的base组件是相应的变量对象(或若未找到则为null),属性名组件是向上查找的标示符的名称。引用类型的详细信息在后面已讨论。

标识符解析过程包含与变量名对应属性的查找,即作用域中变量对象的连续查找,从最深的上下文开始,绕过作用域链直到最上层。

这样一来,在向上查找中,一个上下文中的局部变量较之于父作用域的变量拥有较高的优先级。万一两个变量有相同的名称但来自不同的作用域,那么第一个被发现的是在最深作用域中。

我们用一个稍微复杂的例子描述上面讲到的这些。

01var x = 10;
02  
03function foo() {
04  var y = 20;
05  
06  function bar() {
07    var z = 30;
08    alert(x +  y + z);
09  }
10  
11  bar();
12}
13  
14foo(); // 60

对此,我们有如下的变量/活动对象,函数的的[[scope]]属性以及上下文的作用域链:

全局上下文的变量对象是:

1globalContext.VO === Global = {
2  x: 10
3  foo: <reference to function>
4};

在“foo”创建时,“foo”的[[scope]]属性是:

1foo.[[Scope]] = [
2  globalContext.VO
3];

在“foo”激活时(进入上下文),“foo”上下文的活动对象是:

1fooContext.AO = {
2  y: 20,
3  bar: <reference to function>
4};

“foo”上下文的作用域链为:

1fooContext.Scope = fooContext.AO + foo.[[Scope]] // i.e.:
2  
3fooContext.Scope = [
4  fooContext.AO,
5  globalContext.VO
6];

内部函数“bar”创建时,其[[scope]]为:

1bar.[[Scope]] = [
2  fooContext.AO,
3  globalContext.VO
4];

在“bar”激活时,“bar”上下文的活动对象为:

1barContext.AO = {
2  z: 30
3};

“bar”上下文的作用域链为:

1barContext.Scope = barContext.AO + bar.[[Scope]] // i.e.:
2  
3barContext.Scope = [
4  barContext.AO,
5  fooContext.AO,
6  globalContext.VO
7];

对“x”、“y”、“z”的标识符解析如下:

01- "x"
02-- barContext.AO // not found
03-- fooContext.AO // not found
04-- globalContext.VO // found - 10
05 
06- "y"
07-- barContext.AO // not found
08-- fooContext.AO // found - 20
09 
10- "z"
11-- barContext.AO // found - 30

延伸阅读

此文章所在专题列表如下:

  1. 我们应该如何去了解JavaScript引擎的工作原理
  2. JavaScript探秘:编写可维护的代码的重要性
  3. JavaScript探秘:谨慎使用全局变量
  4. JavaScript探秘:var预解析与副作用
  5. JavaScript探秘:for循环(for Loops)
  6. JavaScript探秘:for-in循环(for-in Loops)
  7. JavaScript探秘:Prototypes强大过头了
  8. JavaScript探秘:eval()是“魔鬼”
  9. JavaScript探秘:用parseInt()进行数值转换
  10. JavaScript探秘:基本编码规范
  11. JavaScript探秘:函数声明与函数表达式
  12. JavaScript探秘:命名函数表达式
  13. JavaScript探秘:调试器中的函数名
  14. JavaScript探秘:JScript的Bug
  15. JavaScript探秘:JScript的内存管理
  16. JavaScript探秘:SpiderMonkey的怪癖
  17. JavaScript探秘:命名函数表达式替代方案
  18. JavaScript探秘:对象Object
  19. JavaScript探秘:原型链 Prototype chain
  20. JavaScript探秘:构造函数 Constructor
  21. JavaScript探秘:可执行的上下文堆栈
  22. 执行上下文其一:变量对象与活动对象
  23. 执行上下文其二:作用域链 Scope Chains
  24. 执行上下文其三:闭包 Closures
  25. 执行上下文其四:This指针
  26. JavaScript探秘:强大的原型和原型链
  27. JavaScript函数其一:函数声明
  28. JavaScript函数其二:函数表达式
  29. JavaScript函数其三:分组中的函数表达式
  30. JavaScript函数其四:函数构造器
  31. JavaScript变量对象其一:VO的声明
  32. JavaScript变量对象其二:VO在不同的执行上下文中
  33. JavaScript变量对象其三:执行上下文的两个阶段
  34. JavaScript变量对象其四:关于变量
  35. JavaScript变量对象其五:__parent__ 属性
  36. JavaScript作用域链其一:作用域链定义
  37. JavaScript作用域链其二:函数的生命周期
  38. JavaScript作用域链其三:作用域链特征
  39. JavaScript闭包其一:闭包概论
  40. JavaScript闭包其二:闭包的实现
  41. JavaScript闭包其三:闭包的用法

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多