JavaScript 作用域与变量范围深度解析

作者:拾光

时间:2026-10-23

浏览:92

本文深入解析 JavaScript 中的作用域机制,涵盖全局变量与局部变量的声明方式、函数参数传递对全局变量的影响、块级作用域的缺失以及变量提升现象。重点对比 var 与 let 关键字在作用域、window 属性挂载及暂时性死区方面的差异,帮助开发者规避常见陷阱。

文章目录

JavaScript 变量作用域概述

变量作用域

JavaScript 作为一门脚本语言,其作用域规则与 C、Java 等编译型语言存在显著差异。

全局变量与局部变量的声明机制

全局变量

在 JavaScript 中声明全局变量,主要有以下几种方式:

1. 在函数外部通过 var 关键字进行声明。


var test ="hello";
console.log(test);
function a(){
  test="xx";
  console.log(test);
}
a();
console.log(test);

运行结果如下:

hello xx xx

通过这种方式声明的变量,可以在代码的任何位置被读取和修改。

2. 在函数内部隐式声明变量(不使用 var、let 或 const)。


function a(){
  test=22;
  console.log(test);
}
a();
console.log(test);

运行结果如下:

22 22

由于 JavaScript 是弱类型语言,变量在使用前无需显式定义,因此这种在函数内部直接赋值的方式也会创建全局变量。

接下来看一个反例:


var test="aa";
console.log(test);
function a(test){
  test=22;
  console.log(test);
}
a(test);
console.log(test);

运行结果如下:

aa 22 aa

可以看到,虽然在函数内部修改了 test 的值,但函数外部打印的结果并未改变。这是因为函数参数传递的是值,函数内部的修改仅作用于局部变量,并未影响全局变量。

因此,在函数参数列表中定义的变量并非全局变量,而是局部变量。

反例二:


function a(){
  var test="aa";
  console.log(test);
}
a();
console.log(test);

运行结果如下:

aa notdefine

在函数内部通过 var 声明的变量属于局部变量,在函数外部无法访问。

块级作用域与变量提升现象

变量作用域

JavaScript 的作用域机制与 C、Java 等语言不同,初学者常因此感到困惑,但经过系统学习后可清晰理解。

1. JavaScript 传统上不存在块级作用域(指 var 声明)。


if(1!=1){
  var y=c;
}
console.log(y)
 
if(1==1){
  var x=a;
}
console.log(x);

运行结果如下:

undefine a

上述代码显示,即使在 if 代码块内定义的变量,在 if 块外部也可以访问。如果判断条件成立,块内的声明语句执行,该变量即成为全局可访问状态。

这表明,在代码块中使用 var 声明的变量实际上会被提升到全局作用域(或函数作用域),成为全局变量。

2. JavaScript 中的全局变量都会自动成为 window 对象的属性。


var x=0;
console.log(window.x);

运行结果如下:

0

3. 变量提升(Hoisting)。


var c=0;
function a(){
  console.log(c);
}
a();

运行结果如下:

0


var c=0;
function a(){
  console.log(c);
  var c=11;
}
a();

运行结果如下:

undefine

可以看出,在函数中增加一行声明语句后,运行结果发生了改变。这是由什么机制导致的呢?

实际上,第二个代码块的执行顺序如下:


var c=0;
function a(){
  var c;
  console.log(c);
  c=11;
}
a();

在函数内部,JavaScript 引擎会先将所有 var 声明语句提升到函数作用域的顶部,但不会提升赋值操作。随后,局部变量会覆盖同名的全局变量。在打印 c 时,由于局部变量 c 尚未赋值,因此输出 undefined。

即由于变量提升,局部变量 c 在赋值前被访问,导致结果为 undefined。

变量提升不仅作用于会执行的代码,即使是不满足条件的分支中的变量也会进行提升:


var c=10;
function a(){
  console.log(c);
  if(false) {
    var c = 10;
  }
}
a();

运行结果如下:

undefine

因为在 if 判断中定义了局部变量 c,尽管 if 条件不成立,但 var c = 10 的声明部分仍会被提升,因此打印 c 的结果为 undefined。

let 关键字与块级作用域

4. let 关键字。

通过上述示例,可以看到使用 var 定义变量的主要弊端:

1. var 定义的变量没有块级作用域;

2. var 定义的全局变量会自动成为全局 window 对象的属性;

3. var 变量存在变量提升现象;

let 关键字正是为了解决这些问题而引入的。


for(let i=0;i<5;i++){
  
}
console.log(i);

运行结果如下:

报错

在代码块中定义 let 变量,在外部引用时会报错,这表明 let 具有块级作用域。


let i=10;
console.log(window.i);

运行结果如下:

undefine

let 声明的变量不会成为 window 对象的属性。


var c=10;
function a(){
  console.log(c);
  let c=1;
  console.log(c);
}
a();

在函数内部存在与全局变量同名的 c,因此会覆盖全局变量 c。但由于 let 不存在变量提升,在第一个打印语句访问 c 时,会触发暂时性死区(TDZ)报错。

至此,关于 JavaScript 中作用域及变量范围的分析介绍完毕。如需了解更多相关 JS 变量作用域内容,请搜索本站历史文章或继续浏览后续相关文章,希望大家今后多多支持本站!

实用工具推荐

电子包浆

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

使用 ›
图片压缩

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

使用 ›
相关文章