关于javascript中的从堆栈内存到执行上下文

关于javascript中的从堆栈内存到执行上下文

我GitHub上的菜鸟仓库地址: 点击跳转查看其余相关文章
文章在个人博客上的地址: 点击跳转

        先从计算机角度说一下内存:内存,包括三个部分:只读存储器(ROM)、随机存储器(RAM)和高速缓冲存储器(Cache)。javascript

        而其中,高速缓冲存储器(Cache)又分为三种:一级缓存(L1 Cache)、二级缓存(L2 Cache)、三级缓存(L3 Cache)。java

        当CPU须要数据的时候,就会先找缓存,由于缓存最快,缓存找不到,才去找慢一点的内存,而后找到后继续将数据放入缓存,下次还要的时候,仍是先找缓存。git

        简单来讲,缓存中的数据只是内存的一部分,可是读写速度最快,因此CPU先找它。github

        扯远了,回过头来。算法

        再解释一下常说的“堆内存”、“栈内存”,“栈内存”也叫作“堆栈内存”,不是两个一块儿的总称,实际上就是栈内存,因此我这里就分别说“堆内存”和“栈内存”。缓存

        这里面就有“堆”和“栈”两个概念了。网络

        先说说栈,它是放在是在于一级缓存中的,数据被调用的时候放入存储空间中,而后被调用完成时候,就会被马上释放。函数

        再说堆,它是放在二级缓存中的,它的生命周期由虚拟机的垃圾回收算法来决定。因此调用这些对象的速度要相对来得低一些。this

        举个很简单的例子来解释“堆”和“栈”这两个概念:spa

        栈,有点像汉诺塔那样的套圈圈,一圈一圈地放上去,前面放的都被压在了底部,后面的就压在上面,一层一层叠罗汉,可是取出来的时候,就是后面放上去的先取出来,越早放进去的越后取出来,简单来讲,就是迟来先上岸。

        堆,就像是一堆东西那些,就好像你杂乱的房间,一堆杂物,你想找东西,翻来翻去,找到了,能够拿走,有些东西,你不拿走,放在那里,其实就是垃圾。

        通常来讲,javascript中的数据类型分为基本数据类型和引用数据类型,而基本数据类型中的变量名和变量直接存放在栈内存中,而引用数据类型的变量值其实是存放的一个地址指针,因此它的变量名和变量值也是存放在栈内存中,而地址指向的实际内容,则是存放在堆内存中。

        好了,开始说一下执行上下文了。

        有些人会混淆执行上下文和做用域的概念,后面的文章我会说到做用域和做用域链,如今先说执行上下文。

        从执行上下文的生命周期来讲,包括三个部分:

        一、建立阶段;二、执行阶段;三、执行完毕阶段。

        1、建立阶段

        执行上下文是在函数被调用的时候才建立,主要有三个内容:

        一、建立变量对象;二、初始化做用域链;三、肯定this的指向。

        2、执行阶段

        发生在函数代码执行阶段,主要有三个内容:

        一、变量赋值;二、函数引用;三、执行其余代码。

        3、执行完毕阶段

        主要内容:执行完毕后跳出执行上下文栈,等待被回收。

        关于建立阶段和执行阶段的具体内容,可能你们会有疑惑,里面的具体内容后面文章会慢慢细说。这里单纯说说执行上下文栈。

        举个简单例子,函数里面也会有嵌套函数的状况,就像这样:

//函数father
function father(age){
    var me = age + 20;
    //函数son
    function son(age){
        return age;
    }
    return son(me);
}
father(33);

        既然执行上下文是函数被调用的时候建立的,那么上面这个father函数被调用以后,而后son也被调用了,那它们的执行上下文是什么关系呢?

        在这里,Javascript会利用执行上下文栈(Execution context stack,ECS)来管理执行上下文。

        回想一下前面栈内存的概念就很容易理解。

        当调用某个函数的时候,就会建立执行上下文,并压入执行上下文栈中,当执行完毕的时候,就会从执行上下文栈中跳出,等待被回收。像上面这种函数内嵌套函数的情形,调用father函数的时候,father建立的执行上下文压入栈中,而后开始执行father的函数体内代码,由于father函数还没执行完毕,因此调用son函数时候会将son建立的执行上下文压入栈中,当son执行完毕,就会跳出,而后father执行完毕,继续跳出。这就完成了整个father的执行上下文周期。

        仍是那句,迟来先上岸的感受。就好像下面的图这样(图片引用自网络),下面就是一个执行上下文栈,最底层确定是全局了,而后只要函数没执行完毕继续在函数内调用其它函数的话,其它函数的执行上下文就会接着压上去,最后执行完毕,压在最上面的上下文先清出,而后其它执行上下文又变成最上面的了,而后执行完毕,继续清出,就和图那样了。

        实际状况可能不是图的那样简单,可能清出到EC2那一层的时候,还没执行完这个函数,又调用其它函数,其它的执行上下文又接着压上去了。

        固然,道理都是同样的。
es1.gif

相关文章
相关标签/搜索