JS执行环境Executioncontext(EC)或执行上下文是JS中极其重要的概念执行环境分为三种(全局执行环境、函数执行环境、evel()执行environment)js为每个执行环境关联一个变量对象。环境中定义的所有变量和函数都存储在这个对象中。EC组成JavaScript代码在执行时会进入不同的执行环境(executioncontexts),这些执行环境会形成一个执行环境栈(executioncontextstack)(Executioncontextstack,ECS)。见下图:VariableObjectVariableObject(VO):变量对象就是包含变量的对象,除了我们不能访问外,它与普通对象没有区别。变量对象存储上下文中定义的变量和函数。变量对象和活动对象(AO)其实是一回事,只是变量对象在规范或者引擎实现中,不能在JavaScript环境中使用。在访问时,只有进入一个执行上下文,这个执行上下文的变量对象才会被激活,所以称为激活对象,只能访问被激活的变量对象,即激活对象上的各种属性。活动对象在进入函数执行环境时创建,并通过函数的arguments属性进行初始化。arguments属性值是一个Arguments对象。在变量对象与活动对象的关系进入执行阶段之前,无法访问变量对象(VO)中的属性!但是进入执行阶段后,可变对象(VO)转化为活动对象(AO),可以访问里面的属性,然后开始执行阶段的操作。它们其实是同一个对象,只是处于不同的执行环境的生命周期。AO实际上包含VO。因为除了VO之外,AO还包含函数的参数,以及arguments的特殊对象。也就是说,AO确实在进入执行阶段时被激活,但是除了VO之外,它还包括函数执行时传入的参数和特殊的对象实参。 AO=VO+函数参数+arguments执行环境分析全局执行环境是最外围的执行环境,全局执行环境被认为是window对象,所以所有的全局变量和函数都创建为的属性和方法窗口对象。js的执行顺序是根据函数调用来决定的。调用函数时,函数环境的变量对象被压入环境堆栈。函数执行完后,栈弹出函数的变量对象,把控制权交给上一次执行的环境变量对象。例如:varscope="global";函数fn1(){返回范围;}functionfn2(){返回范围;}fn1();作用域有两种:全局变量和局部变量。全局作用域:最外层函数定义的变量具有全局作用域,即任何内部函数都可以访问它们:eg:varouterVar="outer";函数fn(){console.log(outerVar);}fn();//result:outerlocalscope:局部作用域一般只能在固定的代码片段内访问,在函数外无法访问functionfn(){varinnerVar="inner";}fn();console.log(innerVar);//ReferenceError:innerVarisnotdefined注意:在函数内部声明变量时,必须使用var命令。如果你不使用它,你实际上是在声明一个全局变量!函数fn(){年龄=18;}fn();console.log(age);//让我们来看一个有趣的现象,在18:varscope="global";函数fn(){console.log(作用域);//result:undefinedvarscope="local";console.log(scope);//result:local;}fn();分析:第一个输出其实是undefined,本来以为会访问外部全局变量(scope="global"),结果并没有。这也算是javascript的一个特性吧。只要在函数中定义了一个局部变量,函数在解析的时候就会提前“声明”这个变量,相当于下面的代码:varscope="global";functionfn(){varscope;//预先声明的局部变量console.log(scope);//result:undefinedscope="local";console.log(scope);//result:local;}fn();[[ScoprChain]]Scope链理解:根据内部函数可以访问外部函数变量的机制,通过链式搜索来判断哪些数据可以被内部函数访问。这是作用域链上给出的环境变量。接下来仔细分析作用域链。一个函数在第一次被调用时,会创建一个执行环境(executioncontext)和对应的作用域链,并将作用域链赋予一个特殊的内部属性([scope])。然后用this、arguments(全局环境中不存在arguments)和其他命名参数的值初始化函数的激活对象。当前执行环境的变量对象总是在作用域链的位置0。以上面执行环境分析的小例子为例进行说明:第一次调用fn1时。分析:可以看到fn1活动对象中没有scope变量,于是沿着作用域链(scopechain)向后查找,找到全局变量对象中的scope,于是返回全局变量对象中的scope值。然后分析下面的代码:functionouter(){varscope="outer";函数内部(){返回范围;}返回内部;}varfn=outer();fn();它困难吗?我现在还是不明白。不知道学前端的小伙伴们怎么看?如果你觉得你已经学会了这一节,可以给我留言。实在是看不懂这一段的内容。希望有开会的朋友能给我一些帮助!谢谢!
