深入理解JavaScript执行上下文
只有理解了执行上下文,深入上下才能更好地理解 JavaScript 语言本身,理解比如变量提升,执行作用域,深入上下闭包等
执行上下文
执行上下文是理解当前代码的执行环境。
执行上下文主要是执行三种类型:
全局执行上下文:全局执行环境是最外围的一个执行环境,在浏览器的深入上下全局对象是 window, this指向这个对象 函数执行上下文:可以有无数个,函数被调用的理解时候会被创建。每次调用函数都会创建一个新的执行执行上下文。 eval执行上下文,深入上下很少用。理解每个执行上下文,执行都有三个重要属性:
变量对象 (variable object,深入上下 VO): 每个执行环境都有一个与之关联的变量对象,环境中定义的理解所有变量和函数都保存在这个对象中。虽然我们编写的执行代码无法访问这个对象,但解析器在处理数据时会在后台使用它。在函数上下文中,使用活动对象 (activation object, AO) 来表示变量对象。活动对象和变量对象其实是一个东西,只有当进入一个执行环境时,这个执行上下文的香港云服务器变量对象才会被激活,此时称为 活动对象(AO),只有活动对象上的属性才能被访问。
作用域链(scope chain):当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。 this执行上下文的生命周期:创建 -> 执行 -> 回收
1. 创建阶段:
1.1 创建变量对象: 初始化函数的参数 arguments 函数声明 变量声明举个简单的例子来理解变量对象
function getName(name) { var b = 2; function foo() { }; var bar = function() { }; } getName(lucystar)此时的 AO 大致如下
AO = { arguments: { 0: lucystar, length: 1 }, name: lucystar, b: undefined, foo: reference to function foo(){ }, bar: undefined }上面例子中涉及到了变量提升和函数提升,之前在 从JS底层理解var、let、const这边文章中也介绍过
1.2 创建作用域链函数的作用域在函数定义的时候就确定了。作用域链本身包含变量对象,当查找变量时,会先从当前上下文中的变量对象中查找,如果没有找到,就会从父级执行上下文的变量对象中查找,一直找到全局执行上下文的变量对象
1.3 确定this的指向这部分又分为多种情况,云服务器具体的可以查看另一篇文章 一文理解this&call&apply&bind
2. 执行阶段
执行变量赋值,代码执行
3. 回收阶段
执行上下文出栈被垃圾回收机制进行回收。关于内存回收的内容,可以查看 V8内存管理及垃圾回收机制
执行上下文栈
执行上下文栈是用来管理执行上下文的。在执行上下文创建好后,JavaScript引擎会将执行上下文压入到栈中,通常把这种用来管理执行上下文的栈称为执行上下文栈,又称调用栈。
let a = javascript; function foo() { console.log(foo); bar(); } function bar() { console.log(bar); } foo();为什么基本数据类型存储在栈中,引用数据类型存储在堆中?JavaScript引擎需要用栈来维护程序执行期间的上下文的状态,如果栈空间大了的话,所有数据都存放在栈空间里面,会影响到上下文切换的效率,进而影响整个程序的执行效率。