资讯专栏INFORMATION COLUMN

javascript作用域链详解

NeverSayNever / 2461人阅读

摘要:文章部分实例和内容来自鸟哥的作用域原理首先应该注意几个点函数也是对象因为是在全局作用域当中当执行到时即会产生在当中,函数的运行是在它被定义的作用域当中,而非执行的作用域当中。

文章部分实例和内容来自鸟哥的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:
    }

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:,
        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:
    para:"eve",
},
Global VO={
    this:window,
    app:,
    window:,
    document:
}
]

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

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

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

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

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

[[scope chain]]={
  intro AO={
        
  } ,
  Factory AO={
        name:"laruence",
        intro:,
  },
  Global VO={
        this:window,
        factory:,
        document:,
        window:
  }
}

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

预编译

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

变量提升(hoisting)

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85909.html

相关文章

  • 详解js变量、作用域及内存

    摘要:不是引用类型,无法输出简而言之,堆内存存放引用值,栈内存存放固定类型值。变量的查询在变量的查询中,访问局部变量要比全局变量来得快,因此不需要向上搜索作用域链。 赞助我以写出更好的文章,give me a cup of coffee? 2017最新最全前端面试题 基本类型值有:undefined,NUll,Boolean,Number和String,这些类型分别在内存中占有固定的大小空...

    waltr 评论0 收藏0
  • 闭包详解

    摘要:函数中的闭包闭包是指有权访问另一个函数作用域中的变量的函数。理解闭包预与变量此时返回注意观察下面的输出内容,理解函数的调用时刻和把的赋值给变量时刻这个函数会返回长度为的函数数组。 Javascript函数中的闭包 闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式就是,在一个函数的内部创建另一个函数。 有关创建作用域链以及作用域链有什么作用的细节对于彻底理解闭包至关重...

    lunaticf 评论0 收藏0
  • 闭包全面详解

    摘要:环境由闭包创建时在作用域中的任何局部变量组成。严格来说,闭包需要满足三个条件访问所在作用域函数嵌套在所在作用域外被调用闭包的形成原理先了解的垃圾回收机制会找出不再使用的变量,不再使用意味着这个变量生命周期的结束。 什么是闭包 最原始定义 闭包(closure),是指函数变量可以保存在函数作用域内,因此看起来是函数将变量包裹了起来。 //根据定义,包含变量的函数就是闭包 function...

    qylost 评论0 收藏0
  • 详解js中的闭包

    摘要:定义函数的时候,为什么的值重新从开始了因为又一次运行了函数,生成一个新的的活动对象,所以的作用域链引用的是一个新的值。 前言 在js中,闭包是一个很重要又相当不容易完全理解的要点,网上关于讲解闭包的文章非常多,但是并不是非常容易读懂,在这里以《javascript高级程序设计》里面的理论为基础。用拆分的方式,深入讲解一下对于闭包的理解,如果有不对请指正。 写在闭包之前 闭包的内部细节,...

    chaosx110 评论0 收藏0

发表评论

0条评论

NeverSayNever

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<