JavaScript提升机制Hoisting详解

作者:代码拾荒

时间:2026-10-23

浏览:601

本文深入解析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的执行机制将会变得清晰明了起来。

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

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章