视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
JS执行环境、作用域链、变量对象和活动对象的关系
2020-11-27 19:33:01 责编:小采
文档


EC的组成

当JavaScript代码执行的时候,会进入不同的执行环境(执行上下文),这些执行环境会构成了一个执行环境栈(执行上下文栈)(Execution context stack,ECS)。见下图:

变量对象

变量对象(VO):变量对象即包含变量的对象,除了我们无法访问它外,和普通对象没什么区别。变量对象存储了在上下文中定义的变量和函数声明

变量对象和活动对象(AO)

  1. 活动对象和变量对象其实是一个东西,只是变量对象是规范上的或者说是引擎实现上的,不可在 JavaScript 环境中访问,只有到当进入一个执行上下文中,这个执行上下文的变量对象才会被激活,所以才叫 activation object

,而只有被激活的变量对象,也就是活动对象上的各种属性才能被访问。

  1. 活动对象是在进入函数执行环境时刻被创建的,它通过函数的 arguments 属性初始化。arguments 属性值是 Arguments 对象。

变量对象和活动对象的关系

未进入执行阶段之前,变量对象(VO)中的属性都不能访问!但是进入执行阶段之后,变量对象(VO)转变为了活动对象(AO),里面的属性都能被访问了,然后开始进行执行阶段的操作。

它们其实都是同一个对象,只是处于执行环境的不同生命周期。

 AO 实际上是包含了 VO 的。因为除了 VO 之外,AO 还包含函数的 parameters,以及 arguments 这个特殊对象。也就是说 AO 的确是在进入到执行阶段的时候被激活,但是激活的除了 VO 之外,还包括函数执行时传入的参数和 arguments 这个特殊对象。

   AO = VO + function parameters + arguments

执行环境分析

全局执行环境是最外围的执行环境,全局执行环境被认为是window对象,因此所有的全局变量和函数都作为window对象的属性和方法创建的。
js的执行顺序是根据函数的调用来决定的,当一个函数被调用时,该函数环境的变量对象就被压入一个环境栈中。而在函数执行之后,栈将该函数的变量对象弹出,把控制权交给之前的执行环境变量对象。

eg:

 var scope = "global"; 
 function fn1(){
 return scope; 
 }
 function fn2(){
 return scope;
 }
 fn1();
 fn2();

演示如下:

[[Scope]] 作用域

变量的作用域

变量的作用域就两种:全局变量和局部变量

 全局作用域:最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的:eg:
 var outerVar = "outer";
 function fn(){
 console.log(outerVar);
 }
 fn();//result:outer
 局部作用域:局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无法访问的
 function fn(){
 var innerVar = "inner";
 }
 fn();
 console.log(innerVar);// ReferenceError: innerVar is not defined
 注意:函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!
 function fn(){
 age = 18;
 }
 fn();
 console.log(age);// 18

再来看一个有趣的现象:

 var scope = "global";
 function fn(){
 console.log(scope);//result:undefined
 var scope = "local";
 console.log(scope);//result:local;
 }
 fn();

分析:第一个输出居然是undefined,原本以为它会访问外部的全局变量(scope=”global”),但是并没有。这可以算是javascript的一个特点,只要函数内定义了一个局部变量,函数在解析的时候都会将这个变量“提前声明”,他就等价于下面的代码:

 var scope = "global";
 function fn(){
 var scope;//提前声明了局部变量
 console.log(scope);//result:undefined
 scope = "local";
 console.log(scope);//result:local;
 }
 fn();

[[Scopr Chain]] 作用域链

理解:根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,这就是作用域链

上面给出了环境变量。下面仔细分析下作用域链

当某个函数第一次被调用时,就会创建一个执行环境(execution context)以及相应的作用域链,并把作用域链赋值给一个特殊的内部属性([scope])。然后使用this,arguments(arguments在全局环境中不存在)和其他命名参数的值来初始化函数的活动对象(activation object)。当前执行环境的变量对象始终在作用域链的第0位。以上述执行环境分析的小例子为例进行图解:当第一次调用fn1时。

解析:可以看到fn1活动对象里并没有scope变量,于是沿着作用域链(scope chain)向后寻找,结果在全局变量对象里找到了scope,所以就返回全局变量对象里的scope值。

再分析下面的代码:

 function outer(){
 var scope = "outer";
 function inner(){
 return scope;
 }
 return inner;
 }
 var fn = outer();
 fn();

总结

说实话,这节真的是很难,现在还是似懂非懂,不知道在学前端的小伙伴你们觉得呢?如果你们觉得这节学会了,可以给我留言,我是真心不懂这节的内容,希望有会的小伙伴可以给我点帮助!谢谢!

相关文章:

浅谈javascript中执行环境(作用域)与作用域链

老生常谈原生JS执行环境与作用域

相关视频:

js高级面向对象和组件开发视频教程

下载本文
显示全文
专题