JavaScript提升机制Hoisting详解
本文深入解析JavaScript中的提升机制(Hoisting),通过剖析词法分析、AST生成及代码执行三个阶段,阐明变量与函数声明在编译期的默认赋值行为。重点讲解函数优先原则及var声明的隐式赋值,帮助开发者清晰理解代码执行顺序与结果。
前言
前言
初次接触JavaScript时,我们通常认为代码是严格按顺序执行的,类似于浏览器解析DOM树的过程:遇到JS脚本或外联脚本时暂停DOM解析,下载并执行脚本后再继续解析DOM。
然而,这种认知常常导致在实际开发中遇到问题。
观察以下代码及其输出结果:
var name;
console.log(name); // undefined
name = 'tom';
age = 10;
var age;
console.log(age); // 10
上述代码引发了一个疑问:仅声明name时,打印结果为undefined;按理说,age在重新声明后也应为undefined,但实际输出却是10。这背后的原因是什么?
通常的解释是,这涉及到了变量提升现象。
类似的情况也出现在函数中,参考以下代码:
log();
console.log(name);
var name = 'tom';
function log() {
console.log('this is log');
}
这段代码的输出结果是什么?
输出结果如下:
this is log
undefined
为何会出现这种情形?通用的解释是,函数声明发生了提升。
针对这两种情况,我们统称为提升机制,即常说的Hoisting。
仅用“提升机制”这一术语解释现象,往往让人云里雾里。若以前可能只是不明觉厉地略过,那么究竟为何会出现这种情况?
JavaScript是如何被编译的呢
JavaScript是如何被编译的呢
有时我们会思考,一段JS代码究竟是如何执行的?实际上,在JS代码执行前,通常存在一个编译过程。
该编译过程虽然复杂,但总体遵循固定的步骤,JavaScript只是在此过程中对代码进行了优化处理。
第一、词法分析
词法分析的主要任务是将程序分解为有意义的代码块,以便对分解后的代码块进行解析。
例如,var age = 10;这段代码会被分解为var、age、=、10、;五个词法单元。
这些单元分析完毕后,将被传递给解析器,用于生成相应的AST(抽象语法树)。
第二、解析词法单元
解析词法单元旨在生成AST。那么,什么是AST呢?我们结合一段代码及其生成的AST来查看。

同样是var age = 10;这段代码,被解析器解析为一种树形结构,即抽象语法树AST。你可以通过AST解析器网站查看生成的AST。
抽象语法树可以进一步转换为可执行代码,这涉及编译的第三个阶段。
第三、生成可执行代码
生成可执行代码的过程,相当于将AST转换浏览器或各种语言引擎可执行的代码。
例如常见的Babel,允许我们使用ES6语法开发程序。它依靠编译器将ES6代码编译为ES6的AST,再将ES6的AST转换为ES5或ES3的AST,最终转换为ES5或ES3代码供浏览器执行。
同理,TypeScript的TSC也是一个编译器,其工作原理与Babel相同,只是两者编译出的ES6的AST略有差异,这导致TypeScript无法使用Babel社区中丰富的插件(如eslint等)。
因为eslint语法检查正是基于AST进行的。
那么,上述编译过程有何实际用途?
JavaScript中的声明和赋值
JavaScript中的声明和赋值
理解了语言的编译过程,接下来探讨JavaScript中声明和赋值的流程。
例如,var age = 10;这段代码在JavaScript中的编译方式是怎样的?
在JavaScript中,这段代码大致相当于以下两个过程:
var age = undefined; // 隐式赋值,编译阶段
age = 10; //变量赋值 执行阶段
函数声明也是如此:
// 这一段代码就是一个完整的函数声明,在编译阶段中,会先执行所有声明,才会依次执行代码操作。
function log() {
console.log('this is log')
}
此时,我们再回头思考一下提升机制是什么?
再看提升
再看提升
JavaScript的执行分为两个阶段:编译阶段和执行阶段。据此,所谓的提升机制(考虑到函数定义,有时不称为变量提升)是指JavaScript引擎在编译阶段首先对变量声明和函数声明进行默认赋值,随后在程序执行阶段才真正执行代码。即针对声明先提升,后执行。
注意:函数声明和变量都有提升机制,两者之间存在优先级。这遵循一个原则:函数优先原则。也就是说,函数声明会提升到普通变量声明之前。
总结
总结
变量提升是一个值得探究的概念,只有理解了这个概念,我们理解JavaScript的执行机制将会变得清晰明了起来。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
JavaScript异步发送HTTP请求时怎么优雅地处理错误
2026-11-05 17:10:44
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
