分享-结合demo讲解JS引擎工作原理

时间:2024-04-01 23:36:56

代码如下:

var x = 1;
function A(y){
var x = 2;
function B(z){
console.log(x+y+z);
}
return B;
}
var C = A(1);
C(1);

分析如下:

阶段一:全局初始化阶段

js引擎在进入一段可执行代码时,要完成以下三个初始化工作:

  1. 创建一个全局对象
  2. 构建一个执行环境栈,与此同时创建一个全局执行环境并压入执行环境栈中
  3. 创建一个与全局执行环境相关的变量对象,此变量对象不仅包含全局对象中的所有属性,还包含全局定义的变量x和函数A。

阶段二:执行函数A

当执行函数A(1)时,js引擎要完成以下三个工作:

  1. 创建函数A的执行环境,并将A的执行环境推入执行环境栈顶并获取执行权限。
  2. 创建函数A的作用域链,js中每个函数执行时都会创建自己的执行环境,每个执行环境都有自己的作用域链,当执行环境被创建时,其作用域链初始化为当前函数的scope所包含的对象,即当前函数的作用域对象,而函数的scope是在函数定义时确定的,初始化为函数定义时所处环境的变量对象。
  3. 创建函数A执行环境的变量对象(也叫活动对象),此对象包含函数的形参、arguments对象、this对象以及内部变量和内部函数的定义,然后将此变量对象推入函数A作用域链顶端。 

阶段三:执行函数B 

函数A被执行以后,返回了B的引用,并赋值给了变量C,执行 C(1) 就相当于执行B(1),JS引擎需要完成以下工作:

  1. 创建函数B的执行环境,并将B的执行环境推入执行环境栈顶并获取执行权限。(注意:当函数A返回后,A的执行环境就会从栈中被删除,只留下全局执行环境)
  2. 创建函数B的作用域链,函数B是在函数A中定义的,函数B的作用域链初始化为执行环境A的变量对象。
  3. 创建函数B执行环境的变量对象(活动对象),并将此变量对象推入函数B作用域链的顶端。

  当函数B执行“x+y+z”时,需要对x、y、z 三个标识符进行一一解析,解析过程遵守变量查找规则:先查找自己的变量对象(活动对象)中是否存在该属性,如果存在,则停止查找并返回;如果不存在,继续沿着其作用域链从顶端依次查找,直到找到为止,如果整个作用域链上都未找到该变量,则返回“undefined”。

函数B的作用域链为:

B的变量对象----->A的变量对象----->全局变量对象

因此,变量x会在A的变量对象中找到,y也会在A的变量对象中找到,z在自己的变量对象中找到 ,结果为2+ 1+ 1 = 4;

总结:

  1. 函数的scope是在定义时确定的。
  2. 函数的作用域链是在执行时确定的。
  3. 函数执行时首先会创建执行环境,然后创建函数的作用域链,接着创建函数的活动对象。          

参考博客地址:http://www.cnblogs.com/onepixel/p/5090799.html(强烈推荐)