javascript作用域链详解

文章部份实例和内容来自鸟哥的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作用域和作用域链

    原文作者:苹果小萝卜
    原文地址: https://segmentfault.com/a/1190000003249960
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞