上下文执行栈
知识点:
* 执行上下文
* 每次函数执行的时候,会产生一个执行上下文,执行上下文是一个对象
* 执行上下文里面会创建一个变量对象 ,里面存放着当前函数内的变量
* 基本数据类型保存在变量对象里的,引用数据数据类型要单独在单堆内存里开辟空间保存。
* 变量对象里保存的就是堆里的内存地址
1 function task(m, n) { 2 var a = 1; 3 var b = { 4 name: '张三' 5 } 6 var c = [1, 2, 3]; 7 } 8 task(10, 20);
我们可以知道task的执行上下文
1 let taskExecutionContext = { 2 this: window, 3 [[Scope]]: [函数的活动对象,全局的变量对象], 4 //Variable Object 变量对象 里面存的是当前函数执行要使用到的变量 5 VO: { 6 m: 10, 7 n: 20, 8 a: 1, 9 b: '内存地址指向对象{name: 张三}', 10 c: '内存地址指向数组[1,2,3]' 11 } 12 }
某个函数第一次被调用时,会创建一个执行环境(execution context)及相应的作用域链,并把作用域链赋值给一个特殊的内部属性(即 [[Scope]] )
当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。
执行环境(execution context,为简单起见,有时也称为“环境”)是JavaScript中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。
执行栈
知识点:
* 执行上下文栈
* 栈是一个数据,里面放着很多执行上下文
* 每次函数执行,都会产生一个执行上下文
* 全局上下文的VO,也被称为GO (Global Object) 全局对象
* 全局对象上的属性可以在任何地方被访问到
* 在浏览端GO就是VO就是window
function one() { var a = 1; var two = () => { var b = 2; var three = () => { var c = 3; debugger console.log(a, b, c); } three(); } two(); } one();
执行上下文对象的VO栈
var executeContextStack = []; //全局上下文 var globalExecuteContext = { VO: { one: '()=>{}' } }
// 全局执行环境是最外层的执行环境 executeContextStack = [globalExecuteContext] var oneExecuteContext = { VO: { a: 1, two: '()=>{}' } }
// 执行到one把one推入环境栈中 executeContextStack = [oneExecuteContext, globalExecuteContext] var twoExecuteContext = { VO: { b: 2, three: '()=>{}' } }
// 执行到two把two推入环境栈中 executeContextStack = [, twoExecuteContext, oneExecuteContext, globalExecuteContext] var threeExecuteContext = { VO: { c: 3 } }
// 执行到three把three推入环境栈中 executeContextStack = [threeExecuteContext, twoExecuteContext, oneExecuteContext, globalExecuteContext]
作用域链的查找过程
function getVariableValue(varName) { for (let i = 0; i < executeContextStack.length; i++) { if (varName in executeContextStack[i].VO) { return executeContextStack[i].VO[varName]; } } }
* 当执行one的时候,会创建一个执行上下文
* 编译阶段
* 创建VO
* 1. 处理参数,把参数放入VO
* 2. 扫描所有代码,找出function声明,从上往下依次执行 在编译阶段,会处理所有的函数声明,如果有重复的声明
* 后面会覆盖前面的声明
* 3.扫描var关键字 var是不赋值,只声明,值是undefined
* 4.在编译阶段不会处理let变量的,let的变量也不会放在VO里
* 编译完成
* 开始执行阶段