← JavaScript数据类型 JavaScript let 变量声明 →

JavaScript var 变量声明

原创 2026-03-11 JavaScript 已有人查阅

JavaScript var 变量声明深度剖析:从历史遗迹到现代实践

在 JavaScript 的发展历程中,var 是最早出现的变量声明方式。它伴随着这门语言从诞生之初一路走来,见证了无数网页的兴衰。虽然现在 let 和 const 已经成为主流,但理解 var 仍然很有必要——你总会碰到一些老项目,或者需要读懂一些历史代码。

var 的语法很简单,就是用 var 关键字后面跟变量名,然后可以通过等号赋值:

// 代码号:https://www.ebingou.cn/
var siteName = "代码号"; 
var courseCount = 128;
var isOnline = true;

console.log(siteName); // 输出:代码号

变量名你可以随便起,但要见名知意;值可以是任何数据类型。看起来很简单对吧?但 var 的背后藏着不少让人头疼的特性。

作用域:函数级而非块级

这是 var 最核心的特征,也是它跟 let/const 的区别。用 var 声明的变量,要么属于全局作用域,要么属于函数作用域,但它无视块级作用域(比如 if 或 for 的花括号)。

函数作用域示例:

// 教程:https://www.ebingou.cn/jiaocheng/
function showMessage() {
    var message = "欢迎学习 JavaScript 教程";
    console.log(message); // 可以访问,输出:欢迎学习 JavaScript 教程
}

showMessage();
console.log(message); // 报错:ReferenceError: message is not defined

变量 message 只在 showMessage 函数内部可见,外部无法访问。这是符合预期的。

缺乏块级作用域的坑:

// 编程:https://www.ebingou.cn/biancheng/
if (true) {
    var learning = "正在学习 var 的特性";
}
console.log(learning); // 输出:正在学习 var 的特性,并没有报错!

for (var i = 0; i < 3; i++) {
    // 循环体
}
console.log(i); // 输出:3,循环计数器 i 竟然泄露到了外部!

个人经验分享:这就是 var 最让人诟病的地方。如果你在 if 或 for 循环里声明了一个 var 变量,它在外面依然能用。这在复杂逻辑中很容易造成变量污染或意外覆盖。所以我一直建议,新项目请毫不犹豫地放弃 var,用 let 和 const 才是正道。

全局作用域的特殊性

当你在任何函数之外用 var 声明变量,它就变成了全局变量。在浏览器环境中,这个全局变量还会成为 window 对象的属性。

// 源码:https://www.ebingou.cn/yuanma/
var globalVar = "我是一个全局变量";
console.log(window.globalVar); // 输出:我是一个全局变量

这意味着你会无意中覆盖掉浏览器内置的 window 属性,或者被他库的变量覆盖,引起一些很难排查的冲突。

重复声明:可以,但没必要

用 var 可以在同一个作用域里多次声明同一个变量,后面的会覆盖前面的,而且不会报错。

var userName = "Alan";
var userName = "Bob";
console.log(userName); // 输出:Bob

这在大型项目中是个隐患。如果你不小心重复使用了变量名,程序不会提醒你,只会静默覆盖,bug 就这么悄无声息地产生了。相比之下,let 和 const 会直接抛出错误,显然更安全。

变量提升:看不见的移动

变量提升是 var 的另一个重要特性。JavaScript 引擎在代码执行前,会把所有 var 的声明(注意只是声明,不包括赋值)提升到当前作用域的顶部。

console.log(myVar); // 输出:undefined,而不是报错
var myVar = "代码号学习编程";

这段代码的实际执行顺序,引擎理解成:

var myVar; // 声明被提升了
console.log(myVar); // 此时尚未赋值,所以是 undefined
myVar = "代码号学习编程"; // 赋值还在原地

很多人觉得这很反直觉。因为按正常代码逻辑,变量应该先声明才能使用。var 的这种行为容易让人写出先使用后声明的代码,虽然不报错,但得到 undefined 往往不是我们想要的。

与 setTimeout 的经典问题

因为 var 没有块级作用域,它在循环中配合 setTimeout 使用时,会有一个经典的问题:

for (var j = 0; j < 3; j++) {
    setTimeout(function() {
        console.log(j); // 猜猜输出什么?
    }, 100);
}
// 输出:3 3 3,不是 0 1 2

原因就是循环里的 j 是同一个变量。当 setTimeout 的回调函数执行时,循环早已结束,j 已经变成了 3。解决这个问题需要借助闭包或者直接用 let

性能与兼容性

文章里提到了性能优化的例子,缓存数组长度确实是个好习惯,不过这跟 var 本身关系不大,而是通用的性能技巧。

// 一个简单的性能优化写法
var arr = [1, 2, 3, 4, 5];
var len = arr.length; // 缓存长度,避免每次循环都计算
for (var k = 0; k < len; k++) {
    console.log(arr[k]);
}

在兼容方面,var 确实是无敌的,从 JavaScript 诞生第一天起就能用。如果你需要维护 2015 年之前的代码,或者某些极老旧的环境,var 是你唯一的选择。

使用场景分析

什么时候还会用到 var?

  • 维护 2015 年之前的老项目

  • 需要兼容 IE 这类上古浏览器(虽然现在几乎不需要了)

  • 在 Node.js 的某些旧模块中

  • 如果你想在全局对象上挂载一个属性(不过直接写 window.xxx = yyy 更清晰)

什么时候不应该用 var?

  • 所有新的项目、新的代码

  • 任何可以使用 let 和 const 的场景

本节课程知识要点

  • 作用域机制var 是函数作用域全局作用域,没有块级作用域,这导致变量意外泄露。

  • 重复声明var 允许在同一作用域重复声明,带来隐式覆盖的问题。

  • 变量提升var 的声明会被提升至作用域顶部,但初始化不会,提前访问会得到 undefined

  • 全局对象污染:全局 var 变量会成为 window 的属性,增加命名冲突风险。

  • 与异步的坑:在循环中用 var 配合异步操作(如 setTimeout),容易出现意料之外的结果。

  • 现代替代方案:在 ES6 普及的今天,推荐优先使用 let(可变变量)和 const(不可变变量),它们拥有更合理的块级作用域,不存在提升的困扰,也更适合现代 JavaScript 开发。

← JavaScript数据类型 JavaScript let 变量声明 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号