JavaScript提升机制Hoisting详解


Posted in Javascript onOctober 23, 2019

前言

刚接触到JavaScript的时候,便知道JavaScript是按顺序执行的,是如浏览器的解析DOM树一样的流程,解析DOM结构的时候,如果遇到JS脚本或者外联脚本便会停止解析,继续下载脚本之后,执行脚本,然后再解析DOM。

然而,却因此常常碰到问题。

看如下代码以及输出:

var name;
console.log(name);  // undefined
name = 'tom';

age = 10;
var age;
console.log(age); // 10

上面的代码让我们产生了疑惑,我们仅仅声明了name的时候,打印出来值是undefined,按理说,重新声明age之后,age的值应该也是undefined才对,但是输出来的却是10。这究竟是怎么回事儿呢?

我们的通用解释是,遇到了变量提升。

而这样的情况,我们在函数中也会看到,请看下面代码:

log();
console.log(name);
var name = 'tom';
function log() {
  console.log('this is log');
}

上面代码的输出结果是什么?

输出结果:

this is log
undefined

为什么会产生这样的情形呢?我们通用的解释是,函数声明提升了。

而针对这两种情况,就是我们经常遇到的提升机制,也就是我们常说的Hoisting。

而仅仅只是一句提升机制来解释这种现象,还是觉得云里雾里,要是我之前可能也就不明觉厉的哦了一声,然后就不再理会这样的东西了,那么究竟为什么会出现这样的情况呢?

JavaScript是如何被编译的呢

有时候我们会想,一段JS代码是如何执行的呢?其实,在JS代码被执行之前,通常都有一个编译过程。

这个编译过程其实很复杂,但总体来说,逃不过编译过程的步骤,只不过JavaScript是在这个步骤之中对代码做了优化处理。

第一、词法分析

词法分析主要是将一段程序分解成有意义的代码块,便于对分解的代码块做解析。

比如,var age = 10;这一段代码将会被分解成 var、age、=、10、;。这是5个词法单元。

这些单元分析完毕之后,便会给解析器调用,生成相应的AST(抽象语法树)。

第二、解析词法单元

解析词法单元,是为了生成AST,那么到底什么是AST呢,我们来看一段代码以及解析生成的AST。

JavaScript提升机制Hoisting详解

同样是var age = 10;这段代码,被解析器解析成了一段树形结构的结构,这个结构,就是抽象语法树AST。你可以通过这个网站来查看生产的AST:AST解析器

而抽象语法树,又是可以转换成可执行代码。这就涉及到编译的第三个阶段。

第三、生成可执行代码

生成可执行代码的过程,相当于是再把AST转换成浏览器可执行的代码,或者是各种语言引擎可执行的代码。

比如我们常见的babel,可以让我们用ES6的语法去开发程序,其实就是依靠babel编译器,将我们的ES6代码编译成ES6的AST,然后将ES6的AST转换成ES5的AST或者ES3的AST,最后将AST转成ES5或ES3的代码来让浏览器执行。

同理,TypeScript的TSC也是一个编译器,做的事情和babel是一样的,只不过两者编译出来的ES6的AST有略微的差别,这样就造成了TypeScript用不了Babel社区的丰富多样的插件,如eslint等。

因为eslint语法检查,正是基于AST做的。

那么上面这个编译过程有什么用呢?

JavaScript中的声明和赋值

理解了语言的编译过程,那么JavaScript中的声明和赋值又是如何的一个流程呢?

比如,var age = 10;这段代码,在JavaScript中的编译方式是如何呢?

在JavaScript中,这段代码大概相当于是如下两个过程:

var age = undefined;   // 隐式赋值,编译阶段
age = 10;  //变量赋值  执行阶段

函数声明也是如此:

// 这一段代码就是一个完整的函数声明,在编译阶段中,会先执行所有声明,才会依次执行代码操作。
function log() {
  console.log('this is log')
}

这个时候,我们再回头来,想一下提升机制是什么?

再看提升

JavaScript的执行,被分为了两个阶段,分别是编译阶段,以及执行阶段。依照这个来看,所谓的提升机制(有的叫做变量提升,考虑到函数的定义,并未用这个名词),就是JavaScript引擎把变量声明和函数声明在编译阶段首先进行默认赋值,之后,在程序执行阶段,才会被代码真正的执行。也就是说,针对声明先提升,后执行。

注意:函数声明和变量都有提升机制,两者之间也有优先级。这都遵循一个原则:函数优先原则。也就是说,函数声明会提升到普通变量声明之前。

总结

变量提升,是一个值得去探究的概念,只有理解了这个概念,我们理解JavaScript的执行机制将会变得清晰明了起来。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery 初体验(建议学习jquery)
Apr 25 Javascript
在JQuery dialog里的服务器控件 事件失效问题
Dec 08 Javascript
使用 TypeScript 重新编写的 JavaScript 坦克大战游戏代码
Apr 07 Javascript
PageSwitch插件实现100种不同图片切换效果
Jul 28 Javascript
jQuery实现鼠标跟随提示层效果代码(可显示文本,Div,Table,Html等)
Apr 18 Javascript
vue实现商城上货组件简易版
Nov 27 Javascript
微信小程序实现添加手机联系人功能示例
Nov 30 Javascript
JavaScript解决浮点数计算不准确问题的方法分析
Jul 09 Javascript
vue+axios+mock.js环境搭建的方法步骤
Aug 28 Javascript
jquery实现的放大镜效果示例
Feb 24 jQuery
JavaScript使用prototype属性实现继承操作示例
May 22 Javascript
JavaScript缺少insertAfter解决方案
Jul 03 Javascript
使用p5.js实现动态GIF图片临摹重现
Oct 23 #Javascript
p5.js临摹动态图形的方法
Oct 23 #Javascript
Vue 实现点击空白处隐藏某节点的三种方式(指令、普通、遮罩)
Oct 23 #Javascript
p5.js实现动态图形临摹
Oct 23 #Javascript
浅析webpack-bundle-analyzer在vue-cli3中的使用
Oct 23 #Javascript
微信小程序 生成携带参数的二维码
Oct 23 #Javascript
使用p5.js临摹动态图形
Oct 23 #Javascript
You might like
获得Google PR值的PHP代码
2007/01/28 PHP
Discuz! 5.0.0论坛程序中加入一段js代码,让会员点击下载附件前自动弹出提示窗口
2007/04/18 PHP
php中使用parse_url()对网址进行解析的实现代码(parse_url详解)
2012/01/03 PHP
PHP中模拟处理HTTP PUT请求的例子
2014/07/22 PHP
推荐10个提供免费PHP脚本下载的网站
2014/12/31 PHP
php中mysql操作buffer用法详解
2015/03/19 PHP
WordPress中用于更新伪静态规则的PHP代码实例讲解
2015/12/18 PHP
thinkPHP5框架闭包函数与子查询传参用法示例
2018/08/02 PHP
关于图片验证码设计的思考
2007/01/29 Javascript
在javascript中关于节点内容加强
2013/04/11 Javascript
基于js disabled="false"不起作用的解决办法
2013/06/26 Javascript
jquery通过a标签删除table中的一行的代码
2013/12/02 Javascript
jquery $(document).ready()和window.onload的区别浅析
2015/02/04 Javascript
javascript自定义in_array()函数实现方法
2015/08/03 Javascript
jQuery实现的简单百分比进度条效果示例
2016/08/01 Javascript
使用vue-resource进行数据交互的实例
2017/09/02 Javascript
JS中图片压缩的方法小结
2017/11/14 Javascript
nodejs acl的用户权限管理详解
2018/03/14 NodeJs
vue v-model实现自定义样式多选与单选功能
2018/07/05 Javascript
Vue+scss白天和夜间模式切换功能的实现方法
2021/01/05 Vue.js
Python查询阿里巴巴关键字排名的方法
2015/07/08 Python
flask中主动抛出异常及统一异常处理代码示例
2018/01/18 Python
numpy:np.newaxis 实现将行向量转换成列向量
2019/11/30 Python
python numpy 反转 reverse示例
2019/12/04 Python
Python selenium文件上传下载功能代码实例
2020/04/13 Python
Python3.7安装PyQt5 运行配置Pycharm的详细教程
2020/10/15 Python
Python绘制K线图之可视化神器pyecharts的使用
2021/03/02 Python
html5 button autofocus 属性介绍及应用
2013/01/04 HTML / CSS
Jacadi Paris美国官方网站:法国童装品牌
2017/10/15 全球购物
中东地区最大的奢侈品市场:The Luxury Closet
2019/04/09 全球购物
双立人美国官方商店:ZWILLING集团餐具和炊具
2020/05/07 全球购物
介绍一下write命令
2012/09/24 面试题
Java中各种基本数据类型的默认值都是什么
2016/12/22 面试题
户外拓展活动方案
2014/02/11 职场文书
高一新生军训方案
2014/05/12 职场文书
安全生产学习心得体会
2016/01/18 职场文书