zoukankan      html  css  js  c++  java
  • Javascript中函数提升和变量提升

     

    词法分析

    词法分析方法:

    js运行前有一个类似编译的过程即词法分析,词法分析主要有三个步骤:

    • 分析参数
    • 再分析变量的声明
    • 分析函数说明

    具体步骤如下:

    • 函数在运行的瞬间,生成一个活动对象(Active Object),简称AO
    • 分析参数
    1. 函数接收形式参数,添加到AO的属性,并且这个时候值为undefine,例如AO.age=undefine
    2. 接收实参,添加到AO的属性,覆盖之前的undefine
    • 分析变量声明,如var age;或var age=23;
    1. 如果上一步分析参数中AO还没有age属性,则添加AO属性为undefine,即AO.age=undefine
    2. 如果AO上面已经有age属性了,则不作任何修改
    • 分析函数的声明,如果有function age(){}

    把函数赋给AO.age ,覆盖上一步分析的值

    代码例子1

    这样我们先通过一段代码来理解词法分析:

    词法分析阶段:

     等价于:

    • 首先形成Active Object即AO对象
    • 第一步:分析形式参数

    AO.age = undefine

    传入实参即对AO.age=undefine进行覆盖:

    AO.age = 3

    • 第二步:分析局部变量

    存在var age = 27;

    这个时候遵循如果AO.age存在值则不作任何修改,按照第一步分析的最后结果AO.age = 3,所以这里不作任何修改即:

    AO.age = 3

    • 第三步:分析函数的声明,

    因为函数中存在function age(){}函数

    所以按照规则应该将函数赋值给AO.age覆盖第二步分析的AO.age = 3即:

    AO.age = function age(){}

    执行阶段

    执行t1函数,到console.log(age)时,词法分析的最后AO.age= function age(){},所以会打印:

    function age(){}

    var age=27;给age赋值27

    到第二个console.log(age)这个时候age已经重新被赋值27,所以这个时候会打印:

    27

    function age() 并没有调用所以并不会执行

    到第三个console.log(age)这个时候age的值并没有被再次修改,所以这个时候会打印:

    27

    运行js查看结果如下与我们分析的完全相符:

    代码例子2

    和上面的词法分析过程一样

    词法分析阶段:

    等价于:

    • 首先形成Active Object即AO对象
    • 第一步:分析形式参数

    AO.age = undefine

    传入实参即对AO.age=undefine进行覆盖:

    AO.age = 22

    • 第二步:分析局部变量

    第一步中最后得到AO.age = 22

    所以这里var age;以及var age =23 ,因为AO.age属性已经存在值,所以这个时候遵循如果存在则不作任何修改,即:

    AO.age = 22

    • 第三步:分析函数的声明,

    因为函数中存在function age(){}函数

    所以按照规则应该将函数赋值给AO.age覆盖第二步分析的AO.age = 22即:

    AO.age = function age(){}

    执行阶段

    执行t1函数,到console.log(age)时,词法分析的最后AO.age= function age(){},所以会打印:

    function age(){}

    var age=23;给age赋值23

    到第二个console.log(age)这个时候age已经重新被赋值23,所以这个时候会打印:

    23

    function age() 并没有调用所以并不会执行

    到第三个console.log(age)这个时候age的值并没有被再次修改,所以这个时候会打印:

    23

    运行js查看结果如下与我们分析的完全相符:

     

    代码例子3

    词法分析阶段:

    等价于:

    • 首先形成Active Object即AO对象
    • 第一步:分析形式参数

    AO.age = undefine

    传入实参即对AO.age=undefine进行覆盖:

    AO.age = 22

    • 第二步:分析局部变量

    第一步中最后得到AO.age = 22,所以这里遵循,如果AO.age存在值则不作任何修改即:

    AO.age = 22

    • 第三步:分析函数的声明

    因为函数中存在function age(){console.log(age)}函数

    所以按照规则应该将函数赋值给AO.age覆盖第二步分析的AO.age = 22即:

    AO.age = function age(){console.log(age)}

    执行阶段

    执行t1函数,到console.log(age)时,词法分析的最后AO.age= function age(){console.log(age)},所以会打印:

    function age(){console.log(age)}

    age = 23,这个时候会覆盖原来的function age(){console.log(age)},所以第二个console.log(age)会打印:

    23

    function age() 是一个函数表达式,所以不会做任何操作

    age() 这个时候的age还是23,并不是函数表达式,所以这里会报错

    运行js查看结果如下与我们分析的完全相符:

    这里的提示错误确实也是说age不是一个函数

    代码例子4

    词法分析阶段:

    • 首先形成Active Object即AO对象
    • 第一步:分析形式参数

    AO.age = undefine

    传入实参即对AO.age=undefine进行覆盖:

    AO.age = 23

    • 第二步:分析局部变量

    第一步中最后得到AO.age = 23,所以这里遵循,如果AO.age存在值则不作任何修改即:

    AO.age = 23

    • 第三步:分析函数的声明

    因为函数中存在function age(){console.log(age)}函数

    所以按照规则应该将函数赋值给AO.age覆盖第二步分析的AO.age = 23即:

    AO.age = function age(){console.log(age)}

    执行阶段

    执行t1函数,到console.log(age)时,词法分析的最后AO.age= function age(){console.log(age)},所以会打印:

    function age(){console.log(age)}

    function age() 是一个函数表达式,所以不会做任何操作

    age()这个时候age是一个函数表达式,这里会执行function age(){console.log(age)},这个时候函数里console.log(age),age没有被修改所以还是function age(){console.log(age)},即打印:

    function age(){console.log(age)}

    最后一个console.log(age)这里的age没有被修改还是function age(){console.log(age)},所以会打印:

    function age(){console.log(age)}

    运行js查看结果如下与我们分析的完全相符:

     

    代码例子5:

    词法分析阶段:

    • 首先形成Active Object即AO对象
    • 第一步:分析形式参数

    AO.age = undefine

    传入实参即对AO.age=undefine进行覆盖:

    AO.age = 23

    • 第二步:分析局部变量

    第一步中最后得到AO.age = 23,所以这里遵循,如果AO.age存在值则不作任何修改即:

    AO.age = 23

    • 第三步:分析函数的声明

    这里并没有函数声明表达式

    所以最后分析的结果是:

    AO.age = 23

    执行阶段

    执行t1函数,到console.log(age)时,词法分析的最后AO.age=23

    所以第一个console.log(age)会打印

    23

    var age = function () {console.log(age)},这里将var = 23进行覆盖这个时候age是一个函数表达式

    age() 正好调用function () {console.log(age)},这个时候这个函数里的console.log(age),age并没有修改还是一个函数表达式,所以会打印

    function () {console.log(age)}

    最后一个console.log(age)还是打印:

    function () {console.log(age)}

    运行js查看结果如下与我们分析的完全相符:

     

    代码例子6:

    代码例子6和代码例子5的分析基本一样,结果也是一样:

    总结:

    函数提升比变量提升优先级高!

  • 相关阅读:
    python中的编码问题
    CVPR2018 Tutorial 之 Visual Recognition and Beyond
    hdu 1376 Octal Fractions
    hdu 1329 Hanoi Tower Troubles Again!
    hdu 1309 Loansome Car Buyer
    hdu 1333 Smith Numbers
    hdu 1288 Hat's Tea
    hdu 1284 钱币兑换问题
    hdu 1275 两车追及或相遇问题
    hdu 1270 小希的数表
  • 原文地址:https://www.cnblogs.com/joyco773/p/7821429.html
Copyright © 2011-2022 走看看