当前位置

网站首页> 程序设计 > 开源项目 > 程序开发 > 浏览文章

javascript作用域链详解

作者:小梦 来源: 网络 时间: 2024-06-29 阅读:

文章部分实例和内容来自鸟哥的blogJavascript作用域原理

首先应该注意几个点:

  • 函数也是对象

  • variable object(VO)

A variable object is a container of data associated with the execution context. It’s a special object that stores variables and function declarations defined in the context.

    var foo=10;    function func(){};        //因为是在全局作用域当中,so...    Global VO={        foo:10,        func:<function>    }
  • Activation Object(AO)

  • When a function is activated (called) by the caller, a special object, called an activation object is created.

  • It’s filled with formal parameters and the special arguments object (which is a map of formal parameters but with index-properties). The activation object then is used as a variable object of the function context.

  • A function’s variable object is the same simple variable object, but besides variables and function declarations, it also stores formal parameters and arguments object and called the activation object.

    function foo(x,y){        var z=30;        function bar(){};    }    foo(10,20);    //当执行到foo(10,20)时即会产生AO    Activation Object={        z:30,        x:10,        y:20,        bar:<function>,        arguments:{0:10,1:20,length:2}    }
  • Scope Chain(Scope Chain=Activation Object + [[scope]])

A scope chain is a list of objects that are searched for identifiers appear in the code of the context.

  • 在JavaScript当中,函数的运行是在它被定义的作用域当中,而非执行的作用域当中。

先看一段代码:

    var name="laurence?";        function show(){        console.log(name);        var name="laurence?";        console.log(name);    }最后输出: undefined  laurence?Object={    name1:undefined,//第一个输出为undefined,表达式声明的局部变量覆盖全局变量,函数执行到这一语句的时候才进行赋值操作name="laurence?",之前name=undefined    name2:"laurence?",//第二个输出为"laurence?"}window={    name:"laurence?",    show:function()}    

注意点:

  • 函数也是对象

  • 变量提升

  • 函数在定义过程中,会将定义时刻的scope chain链接到这个函数对象的[[scope]]属性上,这个属性包含了函数被创建的作用域中 对象 的集合,同时它的作用域会被创建此函数的作用域中可访问的数据对象填充。(**对象的集合、对象链**)

  • 函数的执行过程中,会创建一个 活动对象 (activation object),该对象包含了所有的局部变量命名参数参数集合this,然后将这个活动对象作为此时作用域链的最前端,每个活动对象都有自己的作用域链,用于标识符的解析,当活动对象被创建时,而它的作用域初始化为当前运行函数的[[scope]]所包含的对象。

var func=function(lps,rps){    var name="XL";    ....}func();
  • var func=function(){ } 相当于匿名函数的执行

  • (在执行函数创建活动对象(Obj)的过程中,会创建一个arguments属性,然后会给这个活动对象添加2个属性名,Obj.lps,Obj.rps对于每一个在这个函数中申明的局部变量和函数定义,都作为该活动对象的同名属性,然后将调用参数赋值给形参,对于缺少的调用参数,赋值为undefined)

//这里func()执行时Obj(AO)={    lps:undefined,    rps:undefined,    arguments:{}    name:"XL"}//创建func()时为全局对象:window(Global VO)={    func:function()}

实际的例子:

function factory(){    var name="laruence";    var intro=function(){        console.log("I'm "+name);    }    return intro;}function app(para){    var name=para;    var func=factory();    func();}app("eve");

当调用app的时候,scope chain是由{window活动对象(全局)}+{app活动对象}组成

此时的[[scope chain]]为(**可访问的数据对象访问**):

[[scope chain]]=[Active Object={    this:window,    arguments:{0:"eve",length:1}    name:'eve'    func:<function>    para:"eve",},Global VO={    this:window,    app:<function>,    window:<object>,    document:<object>}]

当调用进入factory函数体内时(**注意这里,函数的scope chain是在它被定义的时候决定的,而非执行的时候决定的**),此时的factory的scope chain为:

[[scope chain]]={Active Object={    this:window,    arguments:{},    name:"laruence",    intro:<function>,},Global Object(Variable Object)={   this:window,   factory:<function>,   app:<function>,   window:<object>,   document:<object>}}

在定义intro函数的时候,intro函数[[scope]]为:

[[scope chain]]={Object={    name:"laruence",    intro:<function>,    this:<factory>,     //注意这里的this指向    arguments:{}},Gloabal Object={    this:window,    factory:<function>,    document:<object>,    window:<object>}}

factory函数返回后,在app体内调用intro时,发生了标识符的解析,而此时的scope chain是:

[[scope chain]]={  intro AO={        <intro 活动对象>  } ,  Factory AO={        name:"laruence",        intro:<function>,  },  Global VO={        this:window,        factory:<function>,        document:<obeject>,        window:<object>  }}

在intro执行过程中scope chain不包含app活动对象,因此name标识符解析的结果应该是factory活动对象中的name属性,也就是"laruence"

预编译

JS在执行每段代码前都会首先处理var关键字(**函数定义式**)和function定义式(**函数声明式**)

变量提升(hoisting)

1.javascript-the-core(强烈推荐)
2.理解javascript作用域和作用域链

热点阅读

网友最爱