引言:在代码执行时,关于栈内存和堆内存的内存图流程,由于markdown不支持放图片,所以可以私信找我拿
1.全局对象的创建
JS引擎会在执行代码之前,也就是解析代码时,会在我们的堆内存创建一个全局对象:Global Object(简称GO)
JS引擎内部在解析代码时,会创建一个全局对象(伪代码如下):
所有的**作用域(scope)**都可以访问该全局对象;
对象里面会包含一些全局的方法和类,像Math、Date、String、Array、setTimeout等等;
其中有一个window属性是指向该全局对象自身的;
该对象中会收集我们全局定义的变量,并设置成undefined;
全局对象是非常重要的,我们平时之所以能够使用这些全局方法和类,都是在这个全局对象中获取的;
2.执行全局代码
在栈内存中创建全局执行上下文
将VO指向到GO上
从上往下开始执行全局代码,依次对GO对象中的全局变量进行赋值
3.执行函数代码
在执行的过程中遇到函数,就会根据函数体创建一个函数执行上下文(Functional Execution Context,简称FEC),并且加入到执行上下文栈(ECS)中。
函数执行上下文(FEC)包含三部分内容:
AO:在解析函数时,会创建一个Activation Objec(AO);
作用域链:由函数VO和父级VO组成,查找是一层层往外层查找;
this指向:this绑定的值,在函数执行时确定;
其实全局执行上下文(GEC)也有自己的作用域链和this指向,只是它对应的作用域链就是自己本身,而this指向为window。
每次调用函数,都会构建一个新的AO
4.变量环境和记录(VO)
在早期ECMA的版本规范中:每一个执行上下文会被关联到一个变量环境(Variable Object,简称VO),在源代码中的变量和函数声明会被作为属性添加到VO中。对应函数来说,参数也会被添加到VO中。
也就是上面所创建的GO或者AO都会被关联到变量环境(VO)上,可以通过VO查找到需要的属性;
规定了VO为Object类型,上文所提到的GO和AO都是Object类型;
在最新ECMA的版本规范中:每一个执行上下文会关联到一个变量环境(Variable Environment,简称VE),在执行代码中变量和函数的声明会作为**环境记录(Environment Record)**添加到变量环境中。对于函数来说,参数也会被作为环境记录添加到变量环境中。
也就是相比于早期的版本规范,对于变量环境,已经去除了VO这个概念,提出了一个新的概念VE;
没有规定VE必须为Object,不同的JS引擎可以使用不同的类型,作为一条环境记录添加进去即可;
虽然新版本规范将变量环境改成了VE,但是JavaScript的执行过程还是不变的,只是关联的变量环境不同,将VE看成VO即可;
5.作用域和作用域链
函数在执行前就已经确定了其父级作用域,与函数在哪执行没有关系,以函数声明的位置为主;
执行代码查找变量属性时,会沿着作用域链一层层往上查找(沿着scope chain往上找),如果一直找到全局对象中还没有该变量属性,就会报错未定义;