执行上下文
执行上下文(简称上下文),也叫执行环境(我感觉这样更好理解)
每个执行环境都有一个关联的变量对象,虽然访问不到这个变量对象
但是这个执行环境中的定义的变量和函数都在这个对象身上,后台处理数据可以用到它
举个例子:
var a=1;
let b=1;
console.log(window.a);//1,var的全局声明成为宿主环境的属性(浏览器是window对象)
console.log(window.b);//undefined,let的声明不会定义在全局对象上
function add(){
var c=1;
}
console.log(window.c);//undefined
作用域链
而在上下文的代码被执行的时候,会创建变量对象的一个作用域链
作用域链:
决定了各级上下文中的代码在访问变量或函数时的顺序,
而代码正在执行的上下文的变量对象始终在作用域链最顶端
还是那个例子:
var a=1;
let b=1;
function add(){
var c=1;
}
add函数上下文的创建的作用域链就是add->global
此外,局部作用域中定义变量可用于在局部上下文中替换全局变量,从而优先访问
var a=1;
let b=1;
function add(){
var b="1";
console.log(b);//"1"
}
内部上下文可以通过创建的作用域链访问外部上下文的一切,
但外部不可以访问内部
因为外部上下文创建的作用域链中没有内部的上下文
var a=1;
function add(){
var b="1";
console.log(b);//"1"
}
console.log(a);//1
console.log(b);//undefined,全局上下文创建的作用域链只有global,它不能访问内部
上下文在其代码执行完毕后会被销毁(详细见js垃圾回收)
聊聊整个js代码是怎么运行的
这里不得不提到执行栈
当打开网页或终端, 宿主环境(浏览器或node) 会将代码传递给 引擎 去执行,
引擎首先会创建一个全局执行环境。全局环境中的代码自上而下有顺序的执行,
当遇到一个函数时,函数的环境被创建,函数中的代码开始执行;而执行过程中通过作用域链来进行标识符查找。
而在函数执行之后,控制权又返还给之前的环境。
ES 这种类似于 " 栈 " 的控制机制,称为 执行栈 。简单的说,执行环境栈就是一个压栈和出栈的过程。
举个例子来说明怎么运行
let a=1;
let b=2;
function add1(){
console.log(a);//1
function add2(){
console.log(b);//2
}
add2();
}
add1();
这个例子中,全局上下文里定义a,b变量,声明add1函数
然后执行add1(),
add1函数环境被创建,add1函数代码开始执行,执行栈将add1执行环境进栈
add1函数上下文创建了一个变量对象的作用域:add1->global(注意这里add1函数还没有执行)
执行第一条语句:输出a。然后它沿着作用域链去这个a,先在add1里面找,再去global里面找,找到就输出
执行第二条语句:声明一个函数add2
执行第三条语句: 执行add2函数,
add2函数环境被创建,add2函数代码开始执行,执行栈将add2执行环境进栈
, 然后它也创建作用域链:add2->add1->global
然后沿着作用域链找b并输出
至此add2函数执行完,执行栈将add2执行环境退栈,
然后add1函数执行完,执行栈将add1执行环境退栈,
然后整个程序执行完,执行栈将全局环境退栈,栈空,程序结束
上图是对js中执行环境的模拟
总结
执行上下文本质就是执行环境
程序运行到不同作用域下,就创建这样一个新的执行环境去执行里面的代码
而作用域链可以帮助上下文去查找标识符
当打开网页或终端, 宿主环境(浏览器或node) 会将代码传递给 引擎 去执行,
引擎首先会创建一个全局执行环境。全局环境中的代码自上而下有顺序的执行,
当遇到一个函数时,函数的环境被创建,函数中的代码开始执行;而执行过程中通过作用域链来进行标识符查找。
而在函数执行之后,控制权又返还给之前的环境。