最通俗易懂的javascript变量提升详解
本文深入解析JavaScript中的变量提升机制,解释代码为何并非逐行执行。通过区分编译(词法分析)与执行两个阶段,阐明var声明与赋值在时间上的分离。同时对比函数声明与函数表达式的提升差异,以及同名声明的覆盖规则,帮助开发者避免常见的undefined或报错陷阱。
变量提升现象示例
示例代码如下:
a = 'ghostwu';
var a;
console.log( a );
在介绍变量提升概念及规则前,若仅依据现有的JavaScript认知,读者可能推测第3行代码的输出应为undefined。这是因为第2行使用了var a进行变量声明但未赋值,按常理a的值应为undefined。然而,实际运行结果却是ghostwu。造成这一差异的原因将在后文详细阐述。
console.log( a );
var a = 'ghostwu';
针对上述示例,第一行代码看似会引发错误,因为在输出变量a之前并未对其进行定义。但实际运行结果仍为undefined。这种看似违背直觉的现象,常让人误以为JavaScript存在Bug。
JavaScript执行机制:编译与执行
要理解这一现象,需明确以下两点核心概念:
JavaScript代码的执行机制并非简单的逐行顺序执行。
JavaScript引擎处理代码时,主要经历两个步骤:
第一步为编译阶段(也称词法分析或预解释)。
第二步为执行阶段。
此外,当遇到如var a = "ghostwu"这样的变量定义语句时,JavaScript引擎会将其拆解为两个独立的部分处理:var a属于声明部分,发生在编译阶段;而a = 'ghostwu'属于赋值部分,发生在执行阶段。因此,var a声明会被提升至当前作用域的顶部,而赋值操作a = 'ghostwu'则保留在原位等待执行阶段。具体表现如下:
a = 'ghostwu';
var a;
console.log( a );
//上面这段代码经过编译之后,变成下面这样
var a; //被提升到当前作用域的最前面
a = 'ghostwu'; //留在原地,等待执行
console.log( a );
console.log( a );
var a = 'ghostwu';
//上面这段代码,经过编译之后,变成下面这样
var a;
console.log( a );
a = 'ghostwu';
经过编译处理后的代码逻辑,是否清晰了?
函数声明与表达式的提升差异
在进一步讲解之前,需先明确函数定义的两种常见形式:
//函数声明, 形如:
function show(){
console.log( '函数声明方式' );
}
//函数表达式, 形如:
var show = function(){
console.log( '表达式方式' );
}
由于表达式定义与函数声明在编译阶段产生的解释效果不同,理解这一区别至关重要。
show();
function show(){
console.log( a );
var a = 'ghostwu';
}
针对上述代码,编译阶段将如何处理?只需记住以下规则即可:
函数声明会被提升至当前作用域的顶部。
因此,上述代码经过编译处理后,逻辑结构变为:
function show(){ //函数声明被提升到 当前作用域的最前面
var a; //var声明被提升到当前作用域的最前面, 注意,他不会提升到函数的外面, 因为当前的作用域是在函数中
console.log( a );
a = 'ghostwu';
}
show();
基于上述编译后的结构,最终输出结果为undefined。
相比之下,函数表达式不会发生提升现象,具体示例如下:
show(); //报错,show is not a function
var show = function(){
console.log( 'ghostwu' );
}
//对于上面这段表达式代码,经过编译之后:
var show;
show(); //执行之后就是 undefined(), 所以在表达式定义之前,调用函数报错了
show = function(){
console.log( 'ghostwu' );
}
show(); //你好
var show;
function show(){
console.log( '你好' );
}
show = function(){
console.log( 'hello' );
}
同名声明的覆盖规则
上述代码为何会输出'你好'?
原因在于:当存在同名的函数声明与变量声明时,函数声明具有更高的优先级并被优先提升,而变量声明则被忽略。因此,编译后的结果表现为:
function show(){
console.log( '你好' );
}
show(); //你好
show = function(){
console.log( 'hello' );
}
show();//如果这里在调用一次,就是hello, 因为show函数体在执行阶段 被 重新赋值了
若存在多个同名的函数声明,后续的声明会覆盖前面的声明,示例如下:
show(); //how are you
var show;
function show(){
console.log( 'hello' );
}
show = function(){
console.log( '你好' );
}
function show(){
console.log( 'how are you!' );
}
//上面的代码经过编译之后,变成如下形式:
function show(){
console.log( 'how are you!' );
}
show(); //how are you
show = function(){
console.log( '你好' );
}
show(); //如果在这里再执行一次,结果:你好
//思考题: 请问下面的结果是什么? 为什么? 写下你的答案
show();
var a = true;
if( a ){
function show(){
console.log( 1 );
}
}else {
function show(){
console.log( 2 );
}
}
以上关于JavaScript变量提升的详细解析内容分享完毕,希望能为读者提供参考与帮助,同时也欢迎支持本站。
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38
