JavaScript变量作用域与作用域链详解

作者:木棉

时间:2026-10-24

浏览:462

本文深入解析JavaScript的变量作用域机制,重点阐述基于作用域链的变量查找规则、函数级作用域特性以及缺乏块级作用域的影响。通过代码示例说明局部变量优先级、变量提升导致的undefined现象,以及未使用var声明变量对全局对象window的影响。

文章目录

JavaScript变量作用域与作用域链详解

在深入探讨JavaScript变量作用域之前,需要明确几个核心概念。


首先,JavaScript的变量作用域机制依赖于其特有的作用域链结构。


其次,传统JavaScript(ES5及之前)并不具备块级作用域。


最后,在函数内部声明的变量,其有效范围覆盖整个函数体,而不仅限于声明所在的代码块。



JavaScript的作用域链机制

1、JavaScript的作用域链机制


为了直观理解,我们先观察以下代码片段:


代码如下:

 
<script type="text/javascript" language="javascript">
var rain = 1;
function rainman(){
var man = 2;
function inner(){
var innerVar = 4;
alert(rain);
} 
inner(); //调用inner函数
} 
rainman(); //调用rainman函数
</script>

观察 alert(rain); 这一行代码的执行过程。JavaScript引擎首先在 inner 函数内部查找变量 rain 的定义;若未找到,则沿着作用域链向上一级,即在 rainman 函数中查找;若 rainman 中仍未定义,则继续向上查找至全局对象(Global Object)。由于在全局对象中定义了 rain = 1,因此最终 alert 弹出的值为 '1'。


所谓作用域链,是指当JavaScript需要查询变量 x 时,会依次检查作用域链中的各个对象。从当前执行上下文的作用域开始,若未找到该变量,则继续查找外层作用域,直至全局对象。若全程未找到,则抛出引用错误。


上述代码示例中涉及的作用域链对象依次包括:inner 函数的局部作用域、rainman 函数的局部作用域,以及全局的 window 对象。



局部变量优先于全局变量

2、函数体内局部变量优先于同名全局变量


代码如下:

 
<script type="text/javascript" language="javascript">
var rain = 1; //定义全局变量 rain
function check(){
var rain = 100; //定义局部变量rain
alert( rain ); //这里会弹出 100
} 
check();
alert( rain ); //这里会弹出1
</script>

缺乏块级作用域的影响

3、JavaScript缺乏块级作用域


这是JavaScript相较于其他编程语言更为灵活(有时也更具隐蔽性)的一个特性。


仔细分析以下代码,你会发现变量 i、j、k 的作用域实际上是相同的,它们在整个 rainman 函数体内都是可见的,而非仅限于 if 或 for 语句块内。


代码如下:

 
<script type="text/javascript" language="javascript">
function rainman(){
/** 
* rainman函数体内存在三个局部变量 i j k
*/ 
var i = 0;
if( 1 ){
var j = 0;
for( var k = 0 ; k < 3 ; k++ ){
alert( k ); //分别弹出 0 1 2
} 
alert( k ); //弹出3
} 
alert( j ); //弹出0
} 
</script>

函数内变量的有效范围与变量提升

4、函数中声明的变量在整个函数中有效


首先观察以下代码示例。


代码如下:

 
<script type="text/javascript" language="javascript">
function rain(){
var x = 1;
function man(){
x = 100;
} 
man(); //调用man
alert( x ); //这里会弹出 100
} 
rain(); //调用rain
</script>

上述代码表明,变量 x 在 rain 函数的整个生命周期内均可访问,且允许重新赋值。正是基于这一规则,可能会产生一些看似“匪夷所思”的结果,请观察下面的代码。


这是因为在函数 rain 内部,局部变量 x 通过 var x = 'rain-man' 进行了声明,从而在整个函数体内隐藏了同名的全局变量 x。之所以第一个 alert 弹出 'undefined' 而非全局的 1,是因为在 JavaScript 执行初期,局部变量 x 已被声明但尚未初始化(赋值)。


代码如下:

 
<script type="text/javascript" language="javascript">
var x = 1;
function rain(){
alert( x ); //弹出 'undefined',而不是1
var x = 'rain-man';
alert( x ); //弹出 'rain-man'
} 
rain()
</script>

因此,上述 rain 函数的实际行为等同于以下代码:


代码如下:

 
function rain(){
var x;
alert( x );
x = 'rain-man';
alert( x );
} 

隐式全局变量与Window对象属性

5、未使用var关键字定义的变量均为全局变量


代码如下:

 
<script type="text/javascript" language="javascript">
function rain(){
x = 100; //声明了全局变量x并进行赋值
} 
rain();
alert( x ); //会弹出100
</script>

这也是JavaScript初学者常犯的错误,即在函数内部无意遗漏 var 关键字,从而意外地创建了全局变量。


6、全局变量均为window对象的属性


代码如下:

 
<script type="text/javascript" language="javascript">
var x = 100 ;
alert( window.x );//弹出100
alert(x);
</script>

该代码逻辑等同于以下写法:


代码如下:

 
<script type="text/javascript" language="javascript">
window.x = 100;
alert( window.x );
alert(x)
</script>

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章