javascript中的函数,调用对象,作用域链
  YutfIKDT4bbf 2023年11月02日 117 0


学习javascript时最困惑的就是函数及其作用域,钻研了这么久也有了一些心得,以下为个人见解,如果有错误请指出,谢谢~

 

本文中没有讨论通过Function()构造函数创建函数时的情况,因为这种情况下会动态地创建和编译javascript代码,并且创建出来的函数并不使用词法作用域(请参考《JavaScript权威指南》),而是被当作顶级函数来编译。

作用域指的是一个抽象的范围,如果解析一个变量名时能够找到它则说明这个变量存在于这个作用域中。而具体查找的过程则是顺着作用域链从头到尾来查找的。

 

先来看一段代码,默认在全局作用域内执行,方便起见可以直接在Firebug控制台执行:



var a=0;
var b=1;
function F(x)
{
    var b=0;
    arguments.callee.c=1;
    alert(F.c);
    alert(F.e);
    alert(arguments.callee === F);
    function G(y){
        alert(y);
        alert(F.e);
    };   
    G(2);
}
F.e=0;



 

我们知道每个javascript执行环境都有一个和它相关联的作用域链,在顶层代码中(不属于任何函数定义的代码),作用域链只由一个对象构成,即全局对象。因此执行之后作用域链就是全局对象,如下所示(注意我们这时候只是定义了函数,但并没有执行):

javascript中的函数,调用对象,作用域链_作用域

接下来进入重点了,执行以下代码:



F(1);



在执行一个函数时,会根据函数体创建一个调用对象并且把它添加到作用域链的头部,并且更新指向作用域链头部的指针为新创建的调用对象。函数体内部通过var语句声明的局部变量,有名称的嵌套函数以及函数的形式参数都是这个调用对象的属性。此时作用域链如下所示:

javascript中的函数,调用对象,作用域链_作用域链_02

注意F引用的是函数对象,不是调用对象(从作用域链头部开始解析“F”,在全局对象中找到了“F”)。调用对象的属性arguments具有特殊的作用,arguments.callee引用的是该函数的函数对象,即F。因此执行



arguments.callee.c=1;



函数对象F增加了一个属性c,并且定义了嵌套函数G,此时作用域链如下:

javascript中的函数,调用对象,作用域链_javascript_03

因此执行



alert(F.c);
alert(F.e);



依次显示1,0。并且执行



alert(arguments.callee === F);



显示true。

执行



G(2);



由于调用了函数,因此又创建了新的调用对象并且添加到作用域链头部,此时作用域链如下:

javascript中的函数,调用对象,作用域链_作用域_04

所以执行



alert(y);
alert(F.e);



分别显示2,0。

每当退出一个函数便会移除并销毁相对应的调用对象(因为没有任何引用了,所以被垃圾回收了),作用域链也就恢复到了之前的状态,形成了一种类似堆栈的效果。

 

最后来看一下闭包,执行以下代码:



function F(){
    var id=0;
    function G(){
    return id++;
    }
    return G;
}
var H=F();



执行完毕之后虽然已经退出了函数,但是其调用对象依旧存在,因为全局对象H引用了其内部的函数(弧形箭头所示),如下:

javascript中的函数,调用对象,作用域链_ViewUI_05

然后执行



H();



注意此时由于H引用的是G,因此指向作用域链头部的指针会从指向全局对象直接改变为指向根据G函数新创建的调用对象B,B成为了作用域链的头部,然后是之前就已经存在的调用对象A和全局对象。作用域链如下:

javascript中的函数,调用对象,作用域链_ViewUI_06

退出函数之后指向作用域链头部的指针则又重新指向了全局对象,B会被垃圾回收销毁,但是A依然会存在,因为仍然有H引用。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  f18CFixvrKz8   2024年05月20日   86   0   0 JavaScript
  fxrR9b8fJ5Wh   2024年05月17日   47   0   0 JavaScript
  2xk0JyO908yA   2024年04月28日   37   0   0 JavaScript
YutfIKDT4bbf