最通俗易懂的javascript变量提升详解

作者:闭包旅人

时间:2026-10-22

浏览:212

本文深入解析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变量提升的详细解析内容分享完毕,希望能为读者提供参考与帮助,同时也欢迎支持本站。

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章