资讯专栏INFORMATION COLUMN

JavaScript-变量提升(AO、GO)编译、闭包

plokmju88 / 2946人阅读

摘要:是一个解释型语言上明确的说,是一个轻量级的解释型的面向对象的将函数视为一级公民的语言。全局代码在执行的时候,先是变量提升,在全局作用域内添加属性,然后是函数以函数声明创建的函数提升,再是代码执行。那么,很显然,闭包其实就是一个函数。

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: ,  //函数内部参数的类数组对象
    c: true,            //传入的参数,如果没有传递实参,那么值就是undefined
}

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

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

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

AO : {
    arguments: ,
    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。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106270.html

相关文章

  • js预编译过程

    摘要:所以变量声明提升和函数声明提升会出现一个先后顺序预编译过程结束。 先科普: 1.javaScript是解释型语言,就是编译一行,执行一行.....2.javaScript没有块级及作用域......3.javaScript具有变量和函数声明提升功能.....4.AO对象和GO对象....5.预编译就是解决代码执行顺序问题,与java语言类似(jvm).... 例如: (function...

    FWHeart 评论0 收藏0
  • 5分钟读懂JavaScript编译流程

    摘要:大家都知道是解释型语言,既然是解释型语言,就是编译一行,执行一行,那又何来预编译一说呢脚本执行引擎都做了什么呢今天我们就来看看吧。全局域就是一切声明的全局变量,全是的属性等同于函数预编译发生在函数执行前一刻。 大家都知道JavaScript是解释型语言,既然是解释型语言,就是编译一行,执行一行,那又何来预编译一说呢?脚本执行js引擎都做了什么呢?今天我们就来看看吧。 1-JavaScr...

    Baoyuan 评论0 收藏0
  • JavaScript的预编译过程与作用域

    摘要:词法作用域是一种静态作用域这个例子的结果按静态作用域来分析执行函数,先从函数内部查找是否有局部变量,如果没有,就根据书写的位置,查找上面一层的代码,也就是等于,所以结果会打印。静态作用域,决定的是作用域链的顺序。 博客原文地址:https://finget.github.io/2018/03/01/javascriptPrecompile/看不明白的地方欢迎提问,有理解的不对的地方希望...

    ziwenxie 评论0 收藏0
  • javascript作用域,作用域链,[[scope]]属性

    摘要:正式由于作用域链的这种关系,我们就不难理解,为什么和不能通过作用域链向上搜索,因为对和的搜索在当前执行函数的活动对象就停止了。 对于Javascript程序员来说,闭包总会让你觉得既熟悉又陌生,然而它对于开发人员来说却非常重要,javascript里的许多设计模式中都用到了闭包,此处以函数作用域为例。 //示例代码 var a=1; function foo(){ ...

    pkhope 评论0 收藏0
  • JavaScript的预编译过程分析

    摘要:一概念是一个单线程解释型的编程语言。预编译大致可分为步创建对象找形参和变量声明,将形参和变量名作为属性名,值为将实参值和形参统一在函数体里面找函数声明,值赋予函数体。 一、JavaScript概念 JavaScript ( JS ) 是一个单线程、解释型的编程语言。 二、JavaScript语言特点 2.1 单线程 JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能...

    graf 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<