2

JavaScript是一个解释型语言

MDN上明确的说,JavaScript是一个轻量级的、解释型的、面向对象的、将函数视为一级公民的语言。
那么,既然js是一个解释型语言,那它就是在运行时把代码转换成机器可以识别的语言。哪它又为什么会存在变量提升呢?
下面这篇文章给出了解释,在此也特别感谢作者的分享!
https://mp.weixin.qq.com/s/ne...

变量提升、预编译过程

function fn(c){
    console.log(c);  //true
    var c = false;
    console.log(a);  //function a(){}
    var a = 1;
    console.log(a);  //1
    function a(){
        
    };
    console.log(a);  //1
    b();             //函数声明
    var b = function(){
        console.log("函数表达式");
    }
    function b(){    
        console.log( "函数声明" )
    }
    b();             //函数表达式
    var d = 4;
}
fn(true);

上面这个fn方法很简单,相信很多人都能过做出来,但肯定也很多人不理解结果为什么是这样!
那么这个过程是怎样执行的呢:
首先,js在执行前会产生一个GO(Global Object),也就是我们常说的全局作用域。当一个方法被调用的时候会形成一个局部作用域AO(Activation Object)。
全局代码在执行的时候,先是变量提升,在全局作用域内添加属性,然后是函数(以函数声明创建的函数)提升,再是代码执行。
函数在被调用的时候,以上面的fn这个方法为例,进入函数上下文,但是在执行代码之前,经历的阶段:
第一阶段:首先创建一个AO,并包含下列属性:

AO : {
    arguments: <ArgO>,  //函数内部参数的类数组对象
    c: true,            //传入的参数,如果没有传递实参,那么值就是undefined
}

第二阶段:函数内部的函数(以函数声明创建的函数)提升

AO : {
    arguments: <ArgO>,
    c: true,
    a: function a(){},
    b: function b(){ console.log( "函数声明" ) }
}

第三阶段:函数内部的变量提升

AO : {
    arguments: <ArgO>,
    c: true,
    a: function a(){},
    b: function b(){ console.log( "函数声明" ) },
    d: undefined
}

函数内部又定义了变量 var c和var a,当变量提升时,发现AO中已经存在a和c属性,如果变量名称跟已经声明的形参或函数相同,则变量声明不会干扰已经存在的这类属性。如果不相同切不存在,那就会放到AO中,值为undefined。

当上面的这些准备工作做完之后,才会开始执行函数内部的代码,这样就很好明白,函数内部的变量,在什么阶段分别代表什么样的值!

闭包解析

在JavaScript高级程序3中,对闭包的描述是这样的,闭包是指有权访问另一个函数作用域中的变量的函数。那么,很显然,闭包其实就是一个函数。
那么我们怎样通过GO、AO理解闭包呢:

function foo(){
    var a = 1;
    function fnSon(){
        a++;
        console.log(a);
    }
    return fnSon;
}
var fnTest = foo();
fnTest();   //2
fnTest();   //3

当foo这个方法被调用的时候,创建一个AO,当函数执行完之后AO里面包含了变量a、函数fnSon

AO:{
    a:1,
    fnSon: function(){}
}

此时的fnSon被赋值给了fnTest,那么foo方法的AO在执行完之后就没办法被销毁,当fnTest被调用的时候,代码执行完之后,foo的AO对象中的a变成了2,再次调用fnTest的时候就变成3。


xqslsm
21 声望0 粉丝