翻翻过去那场雪
这个题是典型的考查JS的代码执行原理,其执行过程解析如下:1、当JS引擎遇到上面的这段代码时,会创建一个全局执行上下文(一个执行上下文的生命周期包含两个阶段,即创建阶段和执行阶段);2、创建阶段,JS引擎会做如下工作:a,创建变量对象(Variable Object -> VO),注:全局执行上下文和函数执行上下文有一点区别的,全局是没有arguments的相关操作 a-1、查找function函数声明,在VO上添加一个属性,属性名为函数名,属性值为函数在内存中的引用,遇 同名覆盖 a-2、查找var变量声明,在VO上添加一个属性,属性名是变量名,属性值为undefined,遇同名跳过 这一步完成后的结果如下: VO = { a:undefined, func:undefined } b,建立作用域链 作用域链其实就是一个数组,在数组的顶端存放的永远是当前执行上下文的VO对象,在全局执行上下文中,作 用域链中只有一个全局的VO,即 [Global_Context.VO],此时JS引擎还做做一件事情,给当前执行上下文中函数添加个内部属性[[scope]](我们不能使用,仅供JS引擎使用) 比如:fn.[[scope]] = [Global_Context.VO]c,确定this指向这里this->window一个执行上下文创建完成后压入栈3、执行阶段,该阶段主要完成变量赋值、函数调用等等操作,此时 VO(用户不可操作) -> AO(用户可操作)(注:VO/AO是同一个对象,不同阶段的不同叫法)首先遇到 a = 2;JS引擎会去当前执行上下文的作用域链中查找(查找的过程是从第一个AO对象开始,依次查找,如果找到,则返回;否则继续查找,直到全局的AO,如果还找不到,则报错。)这一步完成后的结果是如下:AO={ a:2, /* 注:由于func表达式后面是一个自执行匿名函数,所以func的值最终是自执行匿名函数执行后的结果, 这个自执行匿名函数执行时,也会创建对应的执行上下文,和上面的过程一样的,有自己的AO、作用域链 这里的作用域链是由当前执行上下文的VO和函数的内部属性[[scope]]组合而成,则function(){ a++;alert(a); }此函数 也有内部属性[[scope]]指向父级执行上下文的作用域链,由于function(){ a++;alert(a); }被外部变量引用着,而该函数 的[[scope]]有指向自执行匿名函数的作用域链,所以当自执行匿名函数执行完毕后,执行上下文弹出栈,但不会被销毁,而是 又保存到内存中其他位置。 */ func:function(){ a++; alert(a); }}作用域链 [AO,Global_Context.VO]4、第一次执行func()时,首先会在func的执行上下文的AO中查找a,没有找到,就继续到父级执行上下文的AO中找,找到a是3,然后+1,得45、第二次执行func时,同样的执行过程,首先会在func的执行上下文的AO中查找a,没有找到,就继续到父级执行上下文的AO中找,找到a是4,然后+1,得5上述执行过程涵盖了变量提升、作用域、作用域链、闭包(插一个题外话:为什么闭包可以外部访问内部变量,很多人都知道可以访问,但是为什么能访问? 上面已经给出解释)以上是本人对JS的底层执行原理的大体认识,尚有细枝末节未涉及,不足之处难免,仅供参阅。