前言

JS属于解释型语言,在执行过程中顺序执行,但是会分块先预编译然后才执行。因此在JS中存在一种变量提升的现象。搞懂预编译环节,变量提升自然而然也就懂了。本文讲围绕以下几点进行介绍(变量提升会穿插在其中讲解):

  • 预编译执行步骤
  • 示例演示

预编译执行步骤

预编译发生在函数执行的前一刻,过程如下:

  1. 创建AO对象,执行期上下文(后面更新关于执行期上下文详解)。
  2. 寻找函数的形参和变量声明,将变量和形参名作为AO对象的属性名,值设定为undefined.
  3. 将形参和实参相统一,即更改形参后的undefined为具体的形参值。
  4. 寻找函数中的函数声明,将函数名作为AO属性名,值为函数体。

至此,预编译环节结束,函数中咯变量按照最终AO对象中的值开始执行。接下来,结合示例演示就会更加清晰。

示例演示

我们先来看下面这段代码:

 function fn(a){console.log(a);var a = 123;console.log(a);function a(){};console.log(a);var b = function(){};console.log(b);function d(){};}//调用函数fn(1);
复制代码

接下来我们来按照前面的步骤详细分析它的预编译执行过程:

  1. 创建AO对象
AO{//空对象
}
复制代码
  1. 找形参和变量声明
AO{a : undefined,b : undefined
}
复制代码
  1. 形参和实参相统一
AO{a : 1,b : function(){}
}
复制代码
  1. 找函数声明
AO{a : function a(){},b : undefined,d : function d(){}
}
复制代码

预编译环节就此结束,此时的AO对象已经更新为:

AO{a : function a(){},b : undefined,d : function d(){}
}
复制代码

函数开始逐行顺序执行:

 function fn(a){console.log(a);// 输出functiona(){}var a = 123;//执行到这里重新对a赋,AO对象再一次更新console.log(a);// 输出123function a(){};//预编译环节已经进行了变量提升,故执行时不在看这行代码console.log(a);// 输出123var b = function(){};//这个是函数表达式不是函数声明,故不能提升,会对AO中的b重新赋值console.log(b);//输出function(){}function d(){};}
复制代码

至此,函数执行完毕,销毁AO对象。

我们再来看几个例子,熟悉函数的预编译过程。

示例一:

function test (a,b){console.log(a);c = 0;var c;a = 3;b = 2;console.log(b);function b(){};function d(){};console.log(b);
}
//调用函数
test(1);
复制代码

它的AO创建过程如下(此处省略创建空AO对象的部分,下文同):

AO1{a : undefined,b : undefined,c : undefined
}AO2{a : 1,b : undefined,c : undefined
}AO3{a : 1,b : function b(){},c : undefined,d : function d(){}
}
复制代码

至此预编译环节完成,开始执行:

function test (a,b){console.log(a); //输出1c = 0; //给AO对象中的c重新赋值0var c;//预编译环节变量提升,不再读此行代码a = 3;//给AO对象中的a重新赋值3b = 2;//给AO对象中的b重新赋值2console.log(b);//输出2function b(){};//预编译环节变量提升,执行时不再读这行代码function d(){};//预编译环节变量提升,执行时不再读这行代码console.log(b);//输出2
}
//调用函数
test(1);
复制代码

示例二:

这个例子中我们引入全局对象GO。GO与AO的过程类似

function test(){var a = b = 123;
}
test();
复制代码

此函数的执行过程:先把123赋给b,再声明a,再把b赋给a。此时变量b未经声明就赋值,为全局变量。预编译环节如下:

GO1{b : undefined
}
AO1{a : undefined
}GO2{b : 123;
}
AO2{a : 123;
}
复制代码

示例三 :

console.log(test);
function test(test){console.log(test);var test = 234;console.log(test);function test(){};
}
test(1);
var test = 123;
复制代码

我们来看它的预编译过程:

//执行前(页面加载完成时)生成GO对象
GO1{test : undefined
}
GO2{test : function(){}
}//输出 function test(){...}//执行test()前生成它的AO对象
AO1{test : undefined
}
AO2{test : 1
}
AO3{test : function test(){}
}//预编译结束开始执行test(1);
AO4{test : 234
}
//输出234
复制代码

示例四:

function demo(){console.log(b);if(a){var b = 100;}console.log(b);c = 234;console.log(c);
}
var a;
demo();
a = 10;
console.log(c);
复制代码

我们来看它的预编译过程:

//首先是全局对象GO
GO1{a : undefined
}
G02{a : undefined,demo : function demo(){}
}
//执行demo()前预编译,由于demo中的c未声明就使用故为全局对象//输出undefined
GO3{a : undefined,demo : function demo(){}c : undefined
}
//此时a还是undefined,故不执行if()代码块
//输出还是undefined
GO4{a : undefined,demo : function demo(){}c : 234;
}
//输出234
GO5{a : 10,demo : function demo(){}c : 234;
}
//输出234
复制代码

JS----预编译及变量提升详解相关推荐

  1. JS ES6中export和import详解

    1.Export 模块是独立的文件,该文件内部的所有的变量外部都无法获取.如果希望获取某个变量,必须通过export输出, // profile.js export var firstName = ' ...

  2. AO是什么?GO是什么?深度解析JS预编译遇见AO和GO

    写在前面 三月结束了,四月开始了.希望这个世界早点好起来. 今天是个好日子,好呀嘛好日子.哈哈哈哈哈哈,省里发文件了,终于让我看到了开学的希望,心情格外的舒适. 好了好了,来说说今天都干嘛了吧.今天又 ...

  3. 3种Javascript图片预加载的方法详解

    3种Javascript图片预加载的方法详解 预加载图片是提高用户体验的一个很好方法.图片预先加载到浏览器中,访问者便可顺利地在你的网站上冲浪,并享受到极快的加载速度. 这对图片画廊及图片占据很大比例 ...

  4. js高级第一章--变量提升,函数提升

    js高级第一章–变量提升,函数提升 文章目录 前言 一.什么是js里的提升? 二.js变量提升 三.js函数提升 四.特殊情况 总结 前言 在js中,最基本的声明方式有三种,即:var,let,con ...

  5. 使用VS2010编译MongoDB C++驱动详解

    最近为了解决IM消息记录的高速度写入.多文档类型支持的需求,决定使用MongoDB来解决. 考虑到MongoDB对VS版本要求较高,与我现有的VS版本不兼容,在leveldb.ssdb.redis.h ...

  6. 【转】Android APK反编译就这么简单 详解(附图)

     转自:http://blog.csdn.net/vipzjyno1/article/details/21039349/ [置顶] Android APK反编译就这么简单 详解(附图) 分类: and ...

  7. Nginx内置变量以及日志格式变量参数详解

    Nginx内置变量以及日志格式变量参数详解 $args #请求中的参数值 $query_string #同 $args $arg_NAME #GET请求中NAME的值 $is_args #如果请求中有 ...

  8. js 预编译 解释执行 作用域链 闭包

    <script>var a,b = 1;function c(x){var aa = 2;function d(){var ab = 3;}}var d = function(){//.. ...

  9. ThinkPHP模版引擎之变量输出详解

    ThinkPHP模版引擎之变量输出详解 使用ThinkPHP开发有一定时间了,今日对ThinkPHP的模板引擎变量解析深入了解了一下,做出一些总结,分享给大家供大家参考.具体分析如下: 我们已经知道了 ...

最新文章

  1. OpenDesktop 1.0开放桌面操作系统光盘启动安装过程详细图解
  2. [Win] 利用Memory DC抽取EXE的图标并保存为BMP文件
  3. Elasticsearch技术解析与实战(一)基础概念及环境搭建
  4. mysql mysqli 修改_php mysqli 增删改查操作
  5. redis服务端的maxclient和最大连接空闲时间设置
  6. a卡 n卡 html5性能,实测说明,A卡N卡测试平台
  7. PCB制作仿真、自制51板测试及性能改进
  8. 中国行政区划代码,包括五级行政区划详细代码,县级以上区划地理围栏
  9. #10098. 「一本通 3.6 例 1」分离的路径
  10. figma安装包_Figma软件下载|UI界面设计软件(Figma)下载 v3.0.4 官方版 - 比克尔下载...
  11. segmentation_models.pytorch实战:使用segmentation_models.pytorch图像分割框架实现对人物的抠图
  12. c语言break可以跳出for循环吗,怎么跳出for循环
  13. DELL服务器 一般内存模块安装原则
  14. vm虚拟机安装以及镜像和网路配置
  15. 人工智能教你识别口红色号
  16. 分享时的缩略图不显示问题
  17. 【备忘】【不定时更新】那些有用有趣的网站君们~~
  18. 无人机寻迹要两个单片机吗_基于OpenMV的循迹无人机设计
  19. 关于文献HEVC-The New Glod Standard For Video Compress的理解
  20. 2019年谷歌SEO排名主要因素

热门文章

  1. 新概念英语(1-11)Is this your shirt ?
  2. WIN SERVER8更改MYSQL的datadir后,数据库启动不起来
  3. 如何删除Android系统中的内置应用
  4. dede标签用法(来源网页)
  5. RAID信息存放位置!
  6. 【lucene系列学习二】Lucene实现高亮显示关键词
  7. openstack介绍(二)
  8. LeetCode 239. Sliding Window Maximum
  9. animation of android (1)
  10. 启用密码管理之前创建的用户连接Oracle报ORA-28002处理一则