javascript代码运行机制简单介绍

快乐打工仔 分类:实例代码

本文将通过一个简单的代码实例介绍一下javascript引擎对代码从定义到执行的相关过程,从而加深对作用域作用域链等概念的理解。

在阅读本文之前最好参阅以下几篇文章:

(1).执行上下文可以参阅javascript执行上下文详解一章节。

(2).变量对象可以参阅javascript变量对象详解一章节。

(3).作用域和作用域链可以参阅javascript 作用域和作用域链详解一章节。

以下面的代码为例子做一下介绍:

var x = 1;//定义全局变量x,并赋值为1
function wrap(y){//定义一个全局函数
  var x = 2;//定义一个局部变量,并赋值为2
  function inner(z){//定义一个局部函数
    console.log(x+y+z);//输出值
  }
  return inner;//返回内部函数
}
var f = wrap(3);//将返回的内部函数赋值给变量f
f(1);//调用函数

上面的代码是一个典型的闭包的引用,关于闭包可以参阅javascript闭包概念介绍一章节。

第一阶段:

首先会创建一个全局对象,它的属性或者方法可访问性也是全局的。

全局对象具有唯一性,并且生命周期会伴随整个应用程序。

全局对象创建时,Math,String,Date和document等对象作为其属性存在。

全局对象通常只能够使用别名来访问,比如在web中就是用window来访问全局对象,可以用伪代码表示如下:

//创建一个全局对象
var global = { 
  Math:{},
  String:{},
  Date:{},
  document:{},
  //其他属性
  window:this
}

这个时候,javascript还会构建一个执行环境栈( Execution Context Stack) 。

与此同时,全局执行环境上下文Execution Context(EC)也会被创建,并将其压入执行环境栈中。

执行环境栈的创建目的是为了保证代码能够按照正确的顺序执行。

全局执行环境上下文中还会生一个变量对象(Varibale Object) VO,并把VO指向全局对象。

VO包含全局对象中固有的一些属性,比如Math,String,Date和document等,也包含自定义的函数或者变量。

函数在声明的同时为其创建一个[[Scope]]内部属性,表示如下:

wrap.[[Scope]] = [
  globalContext.VO
];

此时执行环境栈可以用伪代码表示如下:

ECStack = [  //执行环境栈
  EC(G) = {  //全局执行环境上下文
    VO(G):{ //全局变量对象
      ... //包含全局对象原有的属性
      x = 1; //定义变量x
      wrap = function(){}; //定义函数wrap
      A[[scope]] = [globalContext.VO];
    }
  }
];

第二阶段:

当调用wrap()函数之后,会创建一个函数执行上下文,并将这个执行上下文压入执行环境栈的顶部。

此时执行环境栈中有两个执行环境上下文,分别是全局执行环境上下文和函数wrap执行环境上下文。

wrap的执行环境上下文在栈顶,全局执行环境上下文在栈的底部。

函数执行上下文中也会建立变量对象(Varibale Object) VO,不过函数的变量对象通常称之为活动对象(Activation Object) A0。活动对象A0包含函数的形参、arguments对象、this对象、以及局部变量和内部函数的定义。

当执行环境上下文被创建时 ,函数wrap的作用域链(Scope Chain)就会被建立 ,用于标识符解析。

作用域链(Scope Chain)= 当前VO+A[[scope]]。

此时的ECStack结构:

ECStack = [  //执行环境栈
  EC(wrap) = {  //A的执行环境
    [scope]:VO(G), //VO是全局变量对象
    AO(wrap) : { //创建函数wrap的活动对象
      y:3,
      x:2, //定义局部变量x
      inner:function(){}, //定义函数B
      A[[scope]]:[globalContext.VO];
      arguments:[],//在函数中访问的arguments就是AO中的arguments
      this:window
    },
    scopeChain:[
      wrapContext.AO,//wrap函数变量对象
      globalContext.VO//全局变量对象
    ]
  },
  EC(G) = {  //全局执行环境上下文
    VO(G):{ //全局变量对象
      ... //包含全局对象原有的属性
      x = 1; //定义变量x
      wrap = function(){}; //定义函数wrap
      A[[scope]] = [globalContext.VO];
    }
  }
];

对于内部函数执行也是同样的道理,这里就不多介绍了。

javascript代码运行机制简单介绍,这样的场景在实际项目中还是用的比较多的,关于javascript代码运行机制简单介绍就介绍到这了。

javascript代码运行机制简单介绍属于前端实例代码,有关更多实例代码大家可以查看

回复

我来回复
  • 暂无回复内容