什么是执行上下文
执行上下文 就是js 的执行环境
执行环境做什么用?
执行环境是在运行js 语句前进行预编译,编译好的环境,分为全局环境和局部环境。全局环境里的变量叫做全局变量,局部环境内的变量叫做局部变量。
通常函数体内部的变量就是局部变量。
对于全局环境, 我们又称之为
全局上下文全局上下文是打开浏览器就自动创建的,在浏览器中,全局上下文就是我们常说的window对象。
对于函数内部环境, 称之为
函数上下文函数上下文是在函数被调用的时候创建的(记住执行调用的时候)
我们了解了环境和变量,那我们看看js 执行代码的时候都干了什么?
- 语法分析 就是检查缩写的代码是不是合格的。
- 预编译 执行代码前,将左右的代码编译成可逐行的代码
- 解释执行 一行一行的执行
预编译
每个执行上下文都有一个与之相关联的变量对象 (Variable Object, 简称 VO, 初其实就是一个对象:{key : value}形式) , 当前执行上下文中所有的变量和函数都添加在其中。
全局预编译
大概的简述: 代码在执行前会将变量和函数提前声明,放在代码块的最顶端,再进行赋值操作。
全局执行预编译的流程
变量和函数提升到最前面
- 将变量名先定义到VO 中,变量的名作为key,值为undefined
- 再将函数提升到到VO 中,函数的名作为key,值为函数体;
- 如果函数名称和变量名称相同,则覆盖变量,属性值就是函数本身
- 预编译结束以后, 再逐行执行代码
var a = 3;
function a(){
};
console.log(a);
结果 3
console.log(a); // [Function: a]
var a = 1;
function a () {};
console.log(a) // 1
上述代码:如果函数名称和变量名称相同,则覆盖变量,属性值就是函数本身
局部预编译
函数执行上下文是在函数被执行的时候创建的
只要函数不执行, 那么就不会进行函数的预编译
在函数预编译阶段被叫做AO (活动对象)。
函数预编译解析流程
- 遇到变量声明, 变量名作为AO对象的属性名, 属性值置为
undefined - 遇到形参, 形参名作为AO对象的属性名, 属性值置为
undefined - 如果形参名与变量名冲突, 形参会将变量声明覆盖
- 将实参的值赋予形参, 即替换 AO对象中形参的属性值
- 遇到函数声明, 函数名作为AO对象的属性名, 属性值为函数本身
- 如果函数名与变量名冲突, 函数声明会将变量声明覆盖
function b(){
console.log(window)
console.log(b) // f b()
b = 6
console.log(b) // 6
}
b()
//函数的调用之前 全局执行上下文window中产生了b函数体,等待执行
// b 函数的this 指向的 window 所以第一个结果值 是 window 里的 function b()
// 函数体内的b 没有var声明就是全局变量,赋值给 b = 6 就等于给全局的var b = function() {} 赋值,所以 第二次b 的结果是 6
setTimeout(function a(){
debugger;
console.log(a) //定时器内部的函数自动执行 ,执行前形成上下文,变量 a 没有var ,就提升变量到外部作用域, 再声明函数a,当函数a 和变量同名,则覆盖变量a,所以a是函数
a= 8 //变量 a 没有var ,就提升变量到外部作用域 已经被覆盖了
console.log(a) //所以这里的a 也是函数a
},1000)
归纳:函数声明优先级 > 实参 > 变量声明
在上下文执行预解析中,变量声明的优先级是最低的,函数声明的优先级是最高的,函数实参优先级是居于他俩之间的。