本文已参与「新人创作礼」活动,一起开启掘金创作之路。
先看一段代码
var name="echo";
function foo(){
var age=18;
console.log(name);
}
foo();
在执行全局代码之前,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"
执行完的结果如下:
然后执行到2-5行,这部分为函数定义所以并不会执行
最后是第五行foo()
该步骤调用了foo函数
在foo函数的代码执行之前,会创建foo函数的执行上下文压入栈中并且在堆空间中创建foo函数的AO(Active Object)。
foo函数中的代码执行前内存状态:
foo函数内的代码开始执行,执行到第三行 var age=18;foo的AO里的age被修改为18。如下:
然后执行到第四行console.log(name);
会先去foo函数的AO中查找name,但是并未查找到name,就回去它的作用域链上查找,foo函数的执行上下文中制定了它的作用域链:VO+父级作用域。foo函数的VO中·不包含name就回去它的父级作用域查找,foo的父级作用域是全局环境,也就是GO,所以会去GO里查找name,所以会打印"echo"。
最后foo函数调用结束,foo函数的执行上下文被销毁,其在堆空间中的AO也被销毁。即又回到了第二张图的状态。