深入学习JS执行--创建执行上下文(变量对象,作用域链,this)

本篇涉及到的名词:预执行,执行上下文,变量对象,活动对象,作用域链,this等

二、预执行

在上一篇说到,在js代码被执行,执行上下文会被压进执行栈中,但是在此之前还有一步工作要做,就是创建好执行上下文,因为创建好才能被压进去啊。

创建执行上下文就是预执行过程: 接下来说说创建执行上下文的细节部分。

三、创建执行上下文 (1)执行上下文组成

执行上下文:也叫一个执行环境,有全局执行环境和函数执行环境两种。每个执行环境中包含这三部分:变量对象/活动对象作用域链this的值

代码模拟 //可以把执行上下文看作一个对象 exeContext = { VO = [...], //VO代表变量对象,保存变量和函数声明 scopeChain = [...]; //作用域链 thisValue = {...}; //this的值 }

创建执行上下文就是创建变量对象,作用域链和this过程

接下来就分别细说创建变量对象/活动对象,作用域链,this值的过程。

(2)变量对象(variable object)

变量对象中存储了在上下文(环境)中定义的变量和函数声明

创建变量对象(VO)时就是将各种变量和函数声明进行提升的环节:

//用下面代码为例子 console.log(a); console.log(b); console.log(c); console.log(d); var a = 100; b = 10; function c(){}; var d = function(){};

上述代码的变量对象:

//这里用VO表示变量对象 VO = { a = undefined; //有a,a使用var声明,值会被赋值为undefined //没有b,因为b没用var声明 c = function c (){} //有c,c是函数声明,并且c指向该函数 d = undefined; //有d,d用var声明,值会被赋值为undefined }

解说:执行上述代码的时候,会创建一个全局执行上下文,上下文中包含上面变量对象,创建完执行上下文后,这个执行上下文才会被压进执行栈中。开始执行后,因为js代码一步一步被执行,后面赋值的代码还没被执行到,所以使用console.log函数打印各个变量的值是变量对象中的值。

在运行到第二行时会报错(报错后就不再执行了),因为没有b(b is no defined)。把第二行注释掉后,再执行各个结果就是VO里面的对应的值。

讲到这里我想大家对变量对象理解了吧,以及对变量提升和函数提升有个深入了解。

(3)活动对象(activation object)

活动对象是在函数执行上下文里面的,其实也是变量对象,只是它需要在函数被调用时才被激活,而且初始化arguments,激活后就是看做变量对象执行上面一样的步骤。

//例子 function fn(name){ var age = 3; console.log(name); } fn('ry');

当上面的函数fn被调用,就会创建一个执行上下文,同时活动对象被激活

//活动对象 AO = { arguments : {0:'ry'}, //arguments的值初始化为传入的参数 name : ry, //形参初始化为传进来的值 age : undefined //var 声明的age,赋值为undefined }

活动对象其实也是变量对象,做着同样的工作。其实不管变量还是活动对象,这里都表明了,全局执行和函数执行时都有一个变量对象来储存着该上下文(环境内)定义的变量和函数。

(4)作用域链(scope chain)

在创建执行上下文时还要创建一个重要的东西,就是作用域链。每个执行环境的作用域链由当前环境的变量对象及父级环境的作用域链构成。

创建作用域链过程:

//以本段代码为例 function fn(a,b){ var x = 'string', } fn(1,2);

1.函数被调用前,初始化function fn,fn有个私有属性[[scope]],它会被初始化为当前全局的作用域,fn.[[scope]="globalScope"。

2.调用函数fn(1,2),开始创建fn执行上下文,同时创建作用域链fn.scopeChain = [fn.[[scope]]],此时作用域链中有全局作用域。

3.fn活动对象AO被初始化后,把活动对象作为变量对象推到作用域链前端,此时fn.scopeChain = [fn.AO,fn.[[scope]]],构建完成,此时作用域链中有两个值,一个当前活动对象,一个全局作用域。

fn的作用域链构建完成,作用域链中有两个值,第一个是fn函数自身的活动对象,能访问自身的变量,还有一个是全局作用域,所以fn能访问外部的变量。这里就说明了为什么函数中能够访问函数外部的变量,因为有作用域链,在自身找不到就顺着作用域链往上找。

(5)this的值

上面说过执行上下文有两种,一个全局执行上下文,一个函数执行上下,下面分别说说这两种上下文的this。

a.全局执行上下文的this

指向window全局对象

b.函数执行上下文的this(主要讲函数的this)

在《JavaScript权威指南》中有这么几句话:
1.this是关键字,不是变量,不是属性名,js语法不允许给this赋值。
2.关键字this没有作用域限制,嵌套的函数不会从调用它的函数中继承this。
3.如果嵌套函数作为方法调用,其this指向调用它的对象。
4.如果嵌套函数作为函数调用,其this值是window(非严格模式),或undefined(严格模式下)。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzzpz.html