当前位置: 首页 > 科技观察

深入理解JavaScript执行上下文

时间:2023-03-17 23:32:32 科技观察

只有理解了执行上下文才能更好的理解JavaScript语言本身,比如变量提升、作用域、闭包等执行上下文执行上下文就是当前代码的执行环境.执行上下文主要分为三种:全局执行上下文:全局执行环境是最外围的执行环境。浏览器中的全局对象是window,this指向这个对象。函数执行上下文:可以有无数个,当函数被调用时就会被创建。每次调用函数都会创建一个新的执行上下文。eval执行上下文,很少使用。每个执行上下文都有三个重要的属性:变量对象(variableobject,VO):每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都存储在这个对象中。虽然我们编写的代码无法访问此对象,但解析器在处理数据时会在幕后使用它。在函数上下文中,激活对象(AO)用于表示变量对象。活动对象和变量对象其实是一回事。只有进入一个执行环境,这个执行上下文的变量对象才会被激活。此时称为活动对象(AO),只能访问活动对象上的属性。作用域链:当代码在环境中执行时,会创建变量对象的作用域链。作用域链的目的是保证对执行环境有权访问的所有变量和函数的有序访问。这个执行上下文的生命周期:Create->Execute->Recycle1.创建阶段:1.1创建变量对象:初始化函数参数arguments函数声明变量声明举个简单的例子来理解变量对象functiongetName(name){varb=2;functionfoo(){};varbar=function(){};}getName('lucystar')此时的AO大致如下AO={arguments:{0:'lucystar',length:1},name:'lucystar',b:undefined,foo:referencetofunctionfoo(){},bar:undefined}上面的例子涉及变量提升和函数提升。我在从JS底层理解var、let、const一文中也介绍了1.2Creatingscopes。链式函数的作用域是在定义函数时确定的。作用域链本身包含变量对象。查找变量时,会先从当前上下文中的变量对象开始查找。如果没有找到,它会从父执行上下文的变量对象开始查找,直到找到全局执行上下文的变量对象。1.3确定这部分的方向这部分分为多种情况。详细可以参考另一篇文章了解this&call&apply&bind2。在执行阶段执行变量赋值,代码执行3。在回收阶段,将执行上下文弹出栈,由垃圾回收机制回收。内存回收的内容可以查看V8内存管理和垃圾回收机制Executioncontextstack执行上下文栈是用来管理执行上下文的。创建执行上下文后,JavaScript引擎会将执行上下文压入堆栈。通常,这个用来管理执行上下文的栈称为执行上下文栈,也称为调用栈。leta='javascript';functionfoo(){console.log('foo');bar();}functionbar(){console.log('bar');}foo();当上述代码在浏览器中加载时,JavaScript引擎创建一个全局执行上下文并将其压入当前执行堆栈。当遇到foo()函数调用时,JavaScript引擎会创建一个foo函数执行上下文并将其压入当前执行堆栈的顶部。当从foo()函数中调用bar()函数时,JavaScript引擎会创建一个bar函数执行上下文并将其推送到当前执行堆栈的顶部。当函数bar执行完毕后,它的执行上下文从当前栈中弹出,控制流到达下一个执行上下文,也就是foo()函数的执行上下文。当foo()完成执行时,它的执行上下文从堆栈中弹出,控制流到达全局执行上下文。一旦所有代码执行完成,javaScript引擎就会从当前堆栈中删除全局执行上下文。为什么原始数据类型存储在栈中,而引用数据类型存储在堆中?JavaScript引擎在程序执行过程中需要使用栈来维护上下文的状态。如果栈空间很大,所有的数据都会存放在栈空间中,会影响上下文切换的效率,进而影响整个程序的执行效率。