执行上下文就是JavaScript 在被解析和运行时环境的抽象概念,JavaScript 运行任何代码都是在执行上下文环境中运行的,执行上下文包括三个周期:创建——运行——销毁,重点说一下创建环节。
创建环节(函数被调用,但未未被执行)会执行三件事情
- 创建变量对象,首先初始化函数的arguments对象,提升函数声明和变量声明,从近到远查找函数运行所需要的变量。
- 创建作用域链,作用域就是一个独立的地盘,让变量不会相互干扰,当前作用域没有定义的变量,这成为 自由变量。自由变量会向上一直寻找,要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”,如果最终没有就为undefined。这种层层之间就构成了作用域链。
- 确定this指向,this、apply、call的指向
function test(arg){ // 1. 形参 arg 是 "hi" // 2. 因为函数声明比变量声明优先级高,所以此时 arg 是 function console.log(arg); var arg = 'hello'; // 3.var arg 变量声明被覆盖, arg = 'word'被执行 function arg(){ console.log('hello world') } var arg = 'word'; console.log(arg); } test('hi');
可以看下上面这个例子,函数内函数声明比变量声明优先,所以arg被覆盖,并且被提升,所以第一次打印不会报错,打出了arg函数,后面变量被覆盖成为hello。
函数执行多了就会有多个执行上下文,那么怎么管理这些执行上下文呢?
JavaScript 引擎创建了执行栈来管理执行上下文,可以把执行栈认为成一个储存函数调用的栈结构,遵循先进后出的原则。
从上面代码执行,我们大概可以得出以下几点
- JavaScript引擎是单线程执行,所有代码都是排队执行。
- 一开始执行的是全局代码,首先创建全局的执行上下文,然后将该执行上下文压入执行栈中。
- 每当执行一个函数,就会创建该函数的执行上下文,然后将其压入执行栈的顶部,函数执行完成后,执行上下文从底部退出,等待垃圾回收。
- 游览器js总是访问执行栈顶层的执行上下文。
- 全局上下文只有唯一的一个,它在浏览器关闭时出栈