Javascript中函数提升和变量提升
词法分析
词法分析方法:
js运行前有一个类似编译的过程即词法分析,词法分析主要有三个步骤:
- 分析参数
- 再分析变量的声明
- 分析函数说明
具体步骤如下:
- 函数在运行的瞬间,生成一个活动对象(Active Object),简称AO
- 分析参数
- 函数接收形式参数,添加到AO的属性,并且这个时候值为undefine,例如AO.age=undefine
- 接收实参,添加到AO的属性,覆盖之前的undefine
- 分析变量声明,如var age;或var age=23;
- 如果上一步分析参数中AO还没有age属性,则添加AO属性为undefine,即AO.age=undefine
- 如果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的分析基本一样,结果也是一样:

总结:
函数提升比变量提升优先级高!
Javascript中函数提升和变量提升的更多相关文章
- javascript中函数声明、变量声明以及变量赋值之间的关系与影响
javascript中函数声明.变量声明以及变量赋值之间的关系与影响 函数声明.变量声明以及变量赋值之间有以下几点共识: 1.所有的全局变量都是window的属性 2.函数声明被提升到范围作用域的顶端 ...
- javascript中的作用域和变量提升
js的运行主要分两个阶段:js的预解析和运行,预解析阶段所有的变量声明和函数定义都会提前,但是变量的赋值不会提前.
- Javascript中函数及变量定义的提升
<html> <head> <title>函数提升</title> <script language="javascript" ...
- JavaScript中函数的变量提升问题
函数的大体分三种,一种是函数的声明,一种是函数表达式(又称为函数的字面量) 1.函数的声明 => function myFn(){}; 2.函数的表达式 => var myFn = fun ...
- JS 函数作用域及变量提升那些事!
虽然看了多次js函数作用域及变量提升的理论知识,但小编也是一知半解~ 这几天做了几道js小题,对这部分进行了从新的理解,还是有所收获的~ 主要参考书籍: <你不知道的JavaScript(上卷) ...
- JS _函数作用域及变量提升
虽然看了多次js函数作用域及变量提升的理论知识,但也是一知半解~ 这几天做了几道js小题,对这部分进行了从新的理解,还是有所收获的~ 主要参考书籍: <你不知道的JavaScript(上卷)&g ...
- js 函数提升和变量提升
总结: 函数提升比变量提升优先级高! 词法分析 词法分析方法: js运行前有一个类似编译的过程即词法分析,词法分析主要有三个步骤: 分析参数 再分析变量的声明 分析函数说明 具体步骤如下: 函数在运行 ...
- JavaScript中函数函数的定义与变量的声明<基础知识一>
1.JavaScript中函数的三种构造方式 a.function createFun(){ } b.var createFun=function (){ } c.var createFun=new ...
- js函数声明提升与变量提升
变量提升 变量提升: 在指定作用域里,从代码顺序上看是变量先使用后声明,但运行时变量的 “可访问性” 提升到当前作用域的顶部,其值为 undefined ,没有 “可用性”. alert(a); // ...
随机推荐
- 内核探测工具systemtap简介【转】
转自:http://www.cnblogs.com/hazir/p/systemtap_introduction.html systemtap是内核开发者必须要掌握的一个工具,本文我将简单介绍一下此工 ...
- Spring MVC全局异常处理
继承HandlerExceptionResolver接口实现自己的处理方法,如: public class MyHandlerExceptionResolver implements HandlerE ...
- where 和 having区别
WHERE语句在GROUP BY语句之前:SQL会在分组之前计算WHERE语句. HAVING语句在GROUP BY语句之后:SQL会在分组之后计算HAVING语句.
- zookeeper权限问题
对cdrwa的说明如上,网上一些博客乱写误导 参考链接:http://zookeeper.apache.org/doc/r3.1.2/zookeeperProgrammers.html 这是在使用zk ...
- python学习第16天。
内置函数是在原本已经有的序列的基础上,再生成新的. List的方是修改原列表. 内置函数中大部分函数的返回值大部分都是迭代器.生成器. Sorted需要遍历操作,不是单纯的迭代,所以不生成迭代器. 一 ...
- 随机生成游戏用户昵称(nodejs版本)(含机器人头像,金币等)
1 前言 有时需要生成随机的用户(或机器人)昵称,头像,金币等,但又不想太生硬,可以现在网上爬一些常见昵称到文本中,然后读取出来,随机使用即可. 2 代码 var nickNameArr = []; ...
- TIMESTAMPDIFF用法
TIMESTAMPDIFF用法: TIMESTAMPDIFF(interval,datetime_expr1,datetime_expr2) 返回日期或日期时间表达式datetime_expr1 和d ...
- EventBus 3.0使用详解
01 前言 当我们进行项目开发的时候,往往是需要应用程序的各组件.组件与后台线程间进行通信,比如在子线程中进行请求数据,当数据请求完毕后通过Handler或者是广播通知UI,而两个Fragment之家 ...
- 点9图 Android设计中如何切图.9.png
转载自:http://blog.csdn.net/buaaroid/article/details/51499516 本文主要介绍如何制作 切图.9.png(点9图),另一篇姊妹篇文章Android屏 ...
- Glide高级详解—缓存与解码复用
Glide 使用简明的流式语法API,大多数情况下,可能完成图片的设置你只需要:Glide.with(activity) .load(url) .into(imageView); 默认情况下,Glid ...