教程
🎨

前端开发

HTML、CSS、JavaScript 及主流前端框架的实战教程。

JavaScript 变量与数据类型:程序怎么"记住"一个值

用 let / const / var 声明变量有什么区别,JS 里能装哪些数据类型,typeof 怎么看类型,以及最容易踩的类型转换坑。

· 更新于 2026-07-18 阅读量 --

写程序本质上就是在”处理数据”:用户名、商品价格、是否登录、购物车里几件商品……这些数据不能凭空出现,得有个地方先存着、后面再取用。存数据的地方,就叫变量

你可以把变量想象成一个贴了标签的盒子:你往里放东西(赋值),之后凭标签(变量名)就能把东西取出来用。比如 age 这个盒子,今天放 18,明天可以换成 19,但盒子还是那个盒子。程序之所以能”记住”东西、能随着用户操作变化,靠的全是变量。

为什么先学变量

在动手写任何功能之前,你得先知道”数据怎么存”。后面的运算符、条件判断、循环、函数,全都是在操作变量里的值。可以说,变量是 JavaScript 这座大楼的地基。地基没打牢,上面盖什么都晃。

这一篇我们会讲清四件事:怎么声明变量(let/const/var 的区别)、JS 里能装哪些类型的数据、怎么查看一个值的类型、以及新手最容易栽进去的”类型自动转换”大坑。

声明变量的三种方式

JS 里有三种声明关键字,现代写法主要用前两个,第三个是历史遗留。我们先看代码:

let age = 18;        // 可变
const name = '小明'; // 常量,不能再改
var old = '老写法';   // 历史遗留,尽量别用

let:可以重新赋值的变量

let 声明一个可以重新赋值的变量。适合那些”值会变”的场景,比如游戏分数、计数器、用户实时输入。

let score = 60;
console.log(score);   // 60
score = 95;           // ✅ let 可以改
console.log(score);   // 95

注意第 4 行只写 score = 95,不要重复写 letlet 只在”第一次声明”时用一次,之后改值直接写变量名。重复声明 let score = 100 会报错。

const:声明后不可改的常量

const 声明一个常量,赋值后不能再改。能用 const 就尽量用 const,它让代码更可预测——别人(和你三周后的自己)不会意外改掉它,调试时少很多”谁把值改了”的悬案。

const pi = 3.14;
console.log(pi);      // 3.14
// pi = 3.15;         // ❌ 报错:Assignment to constant variable

不过有个容易误解的点:const 锁的是”盒子不能换”,不是”盒子里的内容不能动”。如果盒子里放的是对象或数组,对象内部的属性、数组里的元素还是能改的:

const user = { name: '小明' };
user.name = '小红';   // ✅ 可以,改的是对象内部属性
console.log(user);    // { name: '小红' }
// user = { name: '小刚' };  // ❌ 不行,不能把整个盒子换成另一个对象

var:了解即可,别再用

var 是 ES5 时代的老写法,有两个毛病:一是它没有”块级作用域”(后面讲作用域会细说),容易在循环里出 bug;二是它存在”变量提升”,声明会偷偷跑到作用域顶部,让代码行为难以预测。新项目基本淘汰,看到老代码认识就行,自己写一律用 let/const

经验法则

默认写 const,只有当这个值确实需要被重新赋值时,才改成 let。这能逼着你提前想清楚:这个值到底变不变?

JS 里的数据类型

JS 是”弱类型”语言——你不用提前声明变量装什么类型,赋什么就是什么,甚至同一个变量还能中途换成别的类型(虽然不推荐这么干)。数据类型分两大类:

原始类型(Primitive,直接存值)

这些类型”小而简单”,变量里直接存的就是值本身:

  • string 字符串:'你好'"hello",表示一段文字。
  • number 数字:423.14,JS 不区分整数和小数,统一都是 number
  • boolean 布尔:true / false,表示”真/假""开/关”,是条件判断的核心。
  • null 空值:主动表示”这里有意放了个空”。
  • undefined 未定义:变量声明了但还没赋值时的默认状态。
  • symbol / bigint:较进阶,先知道存在即可,日常少见。

引用类型(Reference,存的是地址)

  • object 对象:包括普通对象 {}、数组 []、函数等。它存的是”这块数据在内存里的地址”,变量里放的是地址牌,不是数据本身。

看代码直观感受一下:

const s = '文字';      // string
const n = 100;        // number
const b = true;       // boolean
const empty = null;   // null
let notSet;           // undefined(没赋值,自动是 undefined)
const obj = { a: 1 }; // object

原始类型和引用类型的区别(重要)

这个区别新手很容易懵,我们用生活比喻讲清楚。原始类型像”名片”——你把名片给别人,对方拿到的是复印件,他涂改自己的复印件,不影响你手里那张。引用类型像”家门钥匙”——你把钥匙配了一把给别人,两人开的是同一扇门,他在屋里挪了沙发,你进去看到的就是被动过的样子。

// 原始类型:各自独立
let a = 5;
let c = a;     // c 拿到 a 的"复印件"
c = 10;
console.log(a); // 5,a 没变

// 引用类型:共享同一块数据
const arr1 = [1, 2, 3];
const arr2 = arr1;   // arr2 拿到的是同一把"钥匙"
arr2.push(4);
console.log(arr1);   // [1, 2, 3, 4],arr1 也跟着变了!

理解这点,能帮你避开”我明明改的是 b,怎么 a 也变了”的诡异 bug。

typeof:查看一个值是什么类型

不确定某个值是什么类型时,用 typeof 问它。它返回一个小字符串告诉你类型:

typeof 'hi'      // "string"
typeof 42        // "number"
typeof true      // "boolean"
typeof {}        // "object"
typeof []        // "object"  ← 数组也是 object,记住
typeof undefined // "undefined"
typeof null      // "object"  ← 历史 bug,记住就行
typeof function(){} // "function"

最后两行是 JS 著名的”坑”:typeof null 竟然返回 "object"typeof 数组也返回 "object"。前者是语言早期的设计失误,改不掉了,记住即可;后者说明光靠 typeof 分不清”普通对象”和”数组”,要区分数组得用 Array.isArray(x)

最容易踩的坑:类型自动转换

JS 在某些情况下会”自作主张”把类型转来转去,常常让人困惑。这就是所谓的”弱类型”带来的副作用:

'5' + 1      // "51"  字符串拼接,数字被转成字符串
'5' - 1      // 4     减法没有拼接语义,字符串被转成数字
'5' * 2      // 10    乘法也一样,字符串被转成数字
1 == '1'     // true  == 会先转换类型再比较
1 === '1'    // false === 严格比较,类型不同直接 false

看第一行:'5' 是字符串,1 是数字,加号遇到字符串就变成”拼接”,于是 1 被变成 '1',拼成 "51"。再看第二行:减号没有”拼接”这回事,JS 就把 '5' 转成数字 5 再减,得到 4。同样是 '5' 配一个数字,加和减结果天差地别,这就是坑。

这就是为什么前面强调永远用 === 而不是 ==== 会帮你偷偷转换类型再比较(1 == '1' 竟然是 true),结果常常不符合直觉;=== 不帮你转换,类型不同直接 false,比较结果更可预测,能避开一大类隐蔽 bug。

实战中正确的做法:先显式把类型转对,再比较:

const input = '18';   // 比如从输入框拿到的,默认是字符串
if (input === 18) {
  console.log('不会进这里,因为 "18" 不等于 18');
}
if (Number(input) === 18) {
  console.log('先把字符串转成数字再比,才进这里');
}

常用的显式转换函数:Number('18') 转数字、String(18) 转字符串、Boolean(0) 转布尔。别依赖 JS 自动帮你转,主动转最安全。

变量命名的讲究

顺带一提,变量名不是随便起的。几条规矩:

  • 只能用字母、数字、下划线 _、美元符 $,且不能以数字开头。
  • 区分大小写:ageAge 是两个不同的变量。
  • 不能用 letconstif 这类”关键字”当名字。
  • 推荐”见名知意”:userNamea 好,cartCountn 好。多个单词用驼峰式(myScore),首字母小写。

这一篇你该记住的

  • 变量像”贴标签的盒子”,用来存和取数据;程序能”记住”东西全靠它。
  • let 存会变的值,用 const 存不变的值,别用 varconst 锁的是盒子不能换,盒子里对象/数组的内容还能改。
  • 数据类型分原始类型(string/number/boolean/null/undefined…)和引用类型(object);引用类型多人共享同一份数据。
  • typeof 看类型,但 typeof null"object"typeof 数组也是 "object" 这两个老坑要记得。
  • 比较一律用 ===,别用会偷偷转类型的 ==;需要时先用 Number() 等显式转换再比。

下一篇我们讲运算符与表达式——加减乘除、> < 比较、还有 && || 这些逻辑运算,它们是把数据”算”出结果的工具,有了变量存值,下一步自然就是”算”起来。