初始化全局对象
node之所以可以执行JavaScript代码是因为它含有v8引擎
JavaScript代码想要被执行就需要js引擎
在解析源代码到AST的过程中会产生一个GlobalObject的对象,这个对象会包含浏览器或者node环境下的全局对象。
globalObject对象中会包含math,console,setTimeout,String,Data这些类
其中的window属性会指向globalObject这个对象本身
1-2的这个解析过程也会把我们写的代码加入到globalObject这个对象里,但并不会给属性赋值,只有当代码被执行时才会赋值
代码被运行前会先从磁盘中取出在加入到内存,在内存中转为机器指令后又到cpu中执行
内存会被划分结构,一个叫栈结构,一个叫堆结构
01 v8引擎为了执行代码,其内部会有一个执行上下文栈(execution context stack,ecstack)(函数调用栈)
这些代码被执行前需要先放到这个栈(ecstack)结构中(一般是存放函数的)
02 因为我们执行的是全局代码,为了全局代码能够正常执行,需要创建全局执行上下文(global execution context)(全局代码需要被执行时才会被创建)
作用域提升
函数被执行的过程
变量在声明前调用会打印undefined;
函数在声明前调用依然会执行函数
js引擎在解析代码时如果发现了函数则会为这个函数在开辟一块内存空间,该空间中包含 该函数的父级作用域(这里是全局作用域)+ 函数执行体(代码块),该空间会有一个内存地址 0x… 。在全局对象中函数的值就是该函数的地址。Go中的函数就是对那个内存空间的一个引用
函数执行前会创建一个指向AO的VO,函数执行完则将VO弹出栈,该VO及Ao就被销毁了;
如果在次执行函数,则又会根据开辟的空间来创建一个新的指向AO的VO。
这样我们就可以理解函数为什么可以在声明前调用。
。
变量的查找
当我们去查找一个变量时,是沿着作用域链去查找的
在编译的过程中父级作用域就被确定了,
开辟的内存空间中存储了该函数的父级作用域,
在指向AO的VO中会存在一个作用域链scope chain :当前函数的AO + 父级作用域的VO;
函数的嵌套,作用域链的查找规则
当在一个函数的作用域中找不到某变量时则会去其父级作用域查找该变量若还未找到则会在往上层找。
函数在编译过程中就已经确定其作用域和父级作用域了,而不是在执行调用的过程才确定。
变量环境和记录
作用域提升面试题