×

JavaScript里var、let、const声明变量有啥区别?

作者:Terry2025.06.26来源:Web前端之家浏览:54评论:0

JavaScript

JavaScript代码时,变量声明用var、let还是const?这仨关键字看着像亲戚,实际“脾气”差别大着呢!想少踩坑、写出更规范的代码,得把它们的区别摸透,今天就唠唠这仨声明方式到底哪里不一样~

var:早期JS里的「自由派」变量

在ES6(2015年)之前,JavaScript里只有var能声明变量,它就像个“自由派”,规则宽松,却藏着不少容易踩的坑。

作用域:只认“函数”,不认“块”

var函数作用域——只要变量在函数里声明,不管被包在iffor这些“小括号”(代码块)里,整个函数都能访问它,举个例子:

function testVar() {
  if (true) {
    var insideIf = '我在if里';
  }
  console.log(insideIf); // 能拿到“我在if里”
}

哪怕insideIf是在if块里声明的,函数里其他地方照样能访问,因为var不认“块”,只认“函数”。

变量提升:声明偷偷“跑”到作用域顶部

var声明的变量会被“偷偷”提到作用域最顶部,但赋值留在原地,比如这样写:

console.log(a); // 输出undefined,不是报错
var a = 10;

JS引擎会偷偷把它变成这样执行:

var a; // 声明被提升到顶部
console.log(a); // 此时a还没赋值,所以是undefined
a = 10; // 赋值留在原来的位置

这种“提升”容易让人误以为变量可以先访问后声明,埋下逻辑隐患。

重复声明:同一个变量能被反复覆盖

同一个作用域里,var能反复声明同一个变量,后面的会把前面的覆盖掉。

var name = '小明';
var name = '小红'; // 不报错,name变成“小红”

虽然代码能跑,但重复声明很容易让变量值“悄悄被改”,调试时一头雾水。

全局污染:全局变量直接挂到window

如果在全局作用域(函数外)用var声明变量,这个变量会直接挂到window对象上。

var globalVar = 2024;
console.log(window.globalVar); // 输出2024

项目大了,全局变量多了,很容易和其他代码“打架”,引发命名冲突。

let:更规矩的「块级作用域」变量

ES6引入let后,JavaScript终于有了块级作用域(用包裹的区域,比如iffor、函数里的代码块)。let就像个“守规矩的新人”,把var的不少坑给填了。

作用域:只在“块”里生效

let块级作用域,变量只在自己的“块”里生效,比如在if块里声明let变量,出了块就访问不到:

if (true) {
  let insideIf = '我是let声明的';
  console.log(insideIf); // 能拿到
}
console.log(insideIf); // 报错:insideIf is not defined

再看循环里的经典场景——用let声明循环变量,每个循环迭代的变量都是独立的:

for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i); // 依次输出0、1、2
  }, 100);
}

如果换成var,所有定时器会共享同一个i,最后输出三个3——这就是var的函数作用域在循环里挖的坑,let的块级作用域完美解决了它。

变量提升:有提升,但多了“临时死区”

let也有提升,但多了个临时死区(TDZ)——变量声明前的区域,访问就报错。

console.log(b); // 报错:ReferenceError: b is not defined
let b = 20;

虽然let的声明被提升了,但JS引擎会“保护”这个变量,在声明前访问就扔错误,逼着你先声明后使用,代码更严谨。

重复声明:同一作用域里不能重复声明

同一个块级作用域里,let不能重复声明同一个变量。

let age = 18;
let age = 20; // 报错:SyntaxError: Identifier 'age' has already been declared

这能避免变量被意外覆盖,减少逻辑错误。

全局挂载:全局声明不挂window

在全局用let声明变量,不会像var那样挂到window上。

let globalLet = '我是let声明的全局变量';
console.log(window.globalLet); // 输出undefined

这样能减少全局命名冲突的风险,让全局作用域更“干净”。

const:「只读」的块级作用域变量

constlet一样是块级作用域,但它更像个“固执的守护者”——声明后基本不能变(特殊情况后面讲)。

声明即赋值:必须立刻给初始值

const声明变量时必须立刻赋值,否则直接报错。

const c; // 报错:SyntaxError: Missing initializer in const declaration

这逼着你在声明时就确定变量的初始值,避免“先声明后赋值”的模糊写法。

基本类型的不可变性

如果const声明的是字符串、数字、布尔值这些基本类型,赋值后就不能再改。

const num = 100;
num = 200; // 报错:TypeError: Assignment to constant variable.

引用类型的「可变」陷阱

如果是引用类型(对象、数组)const锁的是“变量指向的内存地址”,不是内容。

const person = { name: '张三' };
person.name = '李四'; // 不报错,因为对象内容能改
person = { name: '王五' }; // 报错,因为变量指向的内存地址变了

再比如数组:

const arr = [1, 2, 3];
arr.push(4); // 不报错,数组内容变了
arr = [1, 2, 3, 4]; // 报错,数组的内存地址变了

所以用const声明引用类型时,要注意“指针不变,内容可变”这个陷阱。

重复声明:同一作用域里不能重复声明

let一样,const在同一作用域里不能重复声明。

const pi = 3.14;
const pi = 3.1415; // 报错:SyntaxError: Identifier 'pi' has already been declared

var、let、const核心区别总结

为了更直观,咱们从作用域、变量提升、重复声明、初始化、全局挂载、可修改性这几个维度对比下:

维度varletconst
作用域函数作用域块级作用域块级作用域
变量提升完全提升(声明提升,赋值保留)提升但有TDZ(声明前访问报错)提升但有TDZ(声明前访问报错)
重复声明允许(同作用域多次声明,后覆盖前)不允许(同作用域重复声明报错)不允许(同作用域重复声明报错)
初始化要求可先声明后赋值可先声明后赋值必须声明时赋值
全局挂载全局声明→window属性全局声明→不挂window全局声明→不挂window
可修改性可随意修改/重复声明覆盖可修改值,不可重复声明基本类型不可改;引用类型指针不可改、内容可改

写代码时咋选?看场景!

知道了区别,实际开发选哪个更顺手?给几个实用建议:

优先用const:变量不需要重新赋值时

当变量不需要重新赋值时(比如配置对象、固定常量、DOM元素引用),用const更安全,比如定义接口地址、主题配置:

const API_URL = 'https://xxx.com/api';
const themeConfig = { primary: '#ff0000' };

const能防止变量被意外赋值,代码可读性也更强(一看就知道这变量不会变)。

再用let:变量需要重新赋值时

当变量需要在块级作用域内重新赋值时(比如循环变量、条件判断里的临时变量),用let

let count = 0;
for (let i = 0; i < 5; i++) {
  count += i;
}

循环里的ilet保证每个迭代独立;count需要累加,用let随时修改。

尽量不用var:除非维护老项目

除非维护老项目必须兼容(比如公司祖传代码里全是var),否则现代开发优先let/constvar的函数作用域和变量提升太容易埋雷,比如循环里的闭包问题、全局变量污染,debug时能把人搞疯。

选对声明,少踩坑

varletconst的区别吃透,写代码时就能更有“掌控感”,简单说:

  • var是早期JS的“老大哥”,自由但容易闯祸;

  • let是“守规矩的新人”,块级作用域+合理提升,解决了不少var的坑;

  • const是“固执的守护者”,让变量在该稳定的地方稳定下来。

日常开发里,能constconst,需要变用let,除非维护老代码,否则和var说拜拜~这样代码可读性、安全性都能Up!

(偷偷说:现在团队协作开发,基本都要求优先const/letvar已经是“时代的眼泪”啦~)

您的支持是我们创作的动力!
温馨提示:本文作者系Terry ,经Web前端之家编辑修改或补充,转载请注明出处和本文链接:
https://www.jiangweishan.com/article/JavaScriptsdf235235.html

网友评论文明上网理性发言 已有0人参与

发表评论: