js中函数调用前后内存变化

201 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

先看一段代码

var name="echo";
function foo(){
    var age=18;
    console.log(name);
}
foo();

image.png 在执行全局代码之前,js引擎会对该代码进行解析,会生成一个全局执行上下文压入调用栈中,这个全局执行上下文中包含了一个VO对象和Scope Chain(作用域链)。同时会在堆内存中开辟一块空间用来存放产生的GO(Global Object)。全局代码中声明的一些变量和函数都会在执行前被放入GO对象中,全局执行上下文中的VO指向的就是这里的GO。不同的是,变量在GO中的初始值为undefined,只有在执行到相应赋值代码时才会改变GO中该变量的值。而遇到函数声明会在堆中另外为该函数对象开辟一块内存空间,函数对象中包含parentScope(父级作用域)和该函数内的代码体。比如针对上述代码中的foo函数的代码体为 var age=18。GO中存放的函数对应的值只是该函数对象在堆中的地址。 然后看一下代码执行的过程中发生了什么 首先是第一行代码:var name="echo"。 执行完这一步会去GO中寻找name并将其值改为"echo" 执行完的结果如下:

image.png 然后执行到2-5行,这部分为函数定义所以并不会执行 最后是第五行foo() 该步骤调用了foo函数 在foo函数的代码执行之前,会创建foo函数的执行上下文压入栈中并且在堆空间中创建foo函数的AO(Active Object)。 foo函数中的代码执行前内存状态: image.png foo函数内的代码开始执行,执行到第三行 var age=18;foo的AO里的age被修改为18。如下: image.png 然后执行到第四行console.log(name); 会先去foo函数的AO中查找name,但是并未查找到name,就回去它的作用域链上查找,foo函数的执行上下文中制定了它的作用域链:VO+父级作用域。foo函数的VO中·不包含name就回去它的父级作用域查找,foo的父级作用域是全局环境,也就是GO,所以会去GO里查找name,所以会打印"echo"。 最后foo函数调用结束,foo函数的执行上下文被销毁,其在堆空间中的AO也被销毁。即又回到了第二张图的状态。