JS 八大基本类型:一场内存视角的冒险之旅

大家好,今天我们来聊聊 JavaScript 的数据类型。如果你是刚接触 JS 的新手,可能会被 nullundefinedSymbol 这些东西搞得晕头转向。别担心,这篇文章会用最通俗的方式,带你一步步搞懂它们。

一、JS 到底有多少种数据类型?

根据 ECMA262 规范(你可以理解为 JS 的"宪法"),JavaScript 一共有 8 种数据类型。

我们可以把它们分成两大阵营:

javascript 复制代码
原始类型(Primitive Types)--- 6 种(其中 Number 和 BigInt 同属 numeric 数值类)
├── Number    数值
├── String    字符串
├── Boolean   布尔值
├── Null      空
├── Undefined 未定义
├── Symbol    唯一标识符(ES6 新增)
└── BigInt    大整数(ES6 新增)

引用类型(Reference Types)--- 1 种
└── Object    对象

注意:ES6 之前 JS 只有 6 种类型。Symbol 和 BigInt 是后来加入的"新成员"。

二、原始类型:JS 的基本"积木"

原始类型就像乐高积木里最基础的小方块------简单、独立、不可再分。

2.1 Number --- 数字

ini 复制代码
let age = 18;
let price = 99.9;

JS 里所有数字都是 Number 类型,不分整数和浮点数。

但有个大坑 :JS 在存小数时不够精确 。为什么呢?因为计算机底层用的是二进制,像 0.1 + 0.2 这种运算,结果并不是你期望的 0.3

arduino 复制代码
console.log(0.1 + 0.2); // 0.30000000000000004

就像我们无法用十进制精确表示 1/3(0.33333...)一样,计算机也无法用二进制精确表示某些小数。这是所有语言都有的问题,不是 JS 的锅。

2.2 String --- 字符串

ini 复制代码
let name = "小明";
let greeting = '你好';

用单引号或双引号包起来的就是字符串,没什么特别的。

2.3 Boolean --- 布尔值

ini 复制代码
let isLogin = true;
let isVip = false;

只有 truefalse 两个值。常用于条件判断。

2.4 undefined --- "该来的没来"

undefined 只有一个值,就是 undefined。它表示某个东西存在,但还没有被赋值。它是一种"被动"的空。

什么时候你会遇到 undefined?来看这些常见场景:

javascript 复制代码
// 场景1:声明了变量但没赋值
let a;
console.log(a); // undefined

// 场景2:访问对象不存在的属性
let obj = {};
console.log(obj.name); // undefined

// 场景3:函数没有返回值
function noReturn() {
    // 啥也没 return
}
console.log(noReturn()); // undefined

// 场景4:访问数组越界的索引
let arr = [1, 2, 3];
console.log(arr[999]); // undefined

记住一句话:undefined = 该来的没来。你期待这里有个值,但它偏偏没有。

2.5 null --- "故意让它空的"

null 也只有一个值,就是 null。它和 undefined 很像,但含义完全不同:

  • null主动设置的空------你故意告诉 JS:「这个变量我就是想让它空着」。它表示一个"有意设置为空"的对象引用。

  • undefined被动产生的空------系统告诉你:「这个东西还没被初始化」

    let user = null; // "我现在不知道用户是谁,先空着,以后有了再填"

    // 实用技巧:把不用的对象设为 null,帮助浏览器回收内存 let largeData = { data: new Array(10000000).fill("hello") }; largeData = null; // 告诉垃圾回收器:这块内存我不要了,你收走吧

小知识:typeof null === "object" 这是一个历史遗留 bug,别被它误导了------null 确实是原始类型,不是对象。

三、ES6 新增的两个"特种兵"

3.1 Symbol --- 独一无二的标识符

Symbol 是 ES6 引入的新类型,它的核心特点就两个字:唯一

javascript 复制代码
// 即使描述(label)一样,它们也绝对不相等
console.log(Symbol("id") === Symbol("id")); // false!
console.log(typeof Symbol("id")); // "symbol"

每个 Symbol() 创建出来都是世上独一无二的存在。你可以在括号里传一个标签用来调试,但这个标签不影响唯一性

这在需要「绝不重复的 key」时特别好用:

javascript 复制代码
let obj = {
    [Symbol()]: '这个属性不会被意外覆盖',
    prop: "普通属性"
};
console.log(obj.id); // undefined------Symbol 属性不可通过 .id 访问

Symbol 最常见的用途是给对象添加不会冲突的属性名。尤其在写库或框架时,你用 Symbol 做 key,就不用担心跟用户的属性名"撞车"了。

3.2 BigInt --- 超大整数随便算

JS 的 Number 类型有个安全范围:-(2⁵³ - 1)2⁵³ - 1。超出这个范围,计算就会精度丢失。

来看个例子------两个超大数用普通 Number 相加,JS 直接懵了,算出来一个不可信的结果。这时候 BigInt 就派上用场了。只需在数字后面加个 n

ini 复制代码
let num1 = 999999999999999999999999999999999999999999999999999999999999999n;
let num2 = 123456789098765433467324577654789008733233456899003466788924243n;
console.log(num1 + num2); // 精确! ✅
console.log(typeof num1); // "bigint"

注意事项:

sql 复制代码
// console.log(num1 + 1);   // ❌ 报错!BigInt 不能和普通 Number 混算
console.log(num1 + 1n);     // ✅ 必须两边都是 BigInt

四、原始类型 vs 引用类型:拷贝的两种姿势

这是很多初学者最困惑的地方。理解了它,你就真正入门了 JS。

4.1 原始类型:复印机式赋值

ini 复制代码
let a = null;
let b = a;  // 把 a 的值"复印"一份给 b
b = 2;
console.log(a); // null------a 完全不受影响

原始类型的赋值就像复印机------复印一份给你,原件和复印件各管各的,互不影响。

4.2 引用类型:共享地址式赋值

ini 复制代码
let obj = { name: "张三" };
let obj2 = obj;          // obj2 和 obj 指向同一个对象
obj2.company = "字节跳动";
console.log(obj);        // { name: "张三", company: "字节跳动" }
console.log(obj2);       // { name: "张三", company: "字节跳动" }
// 两个输出一模一样!

对象是引用类型,赋值时传的是地址(你可以理解成"门牌号"),而不是实际数据。obj 和 obj2 手里拿的是同一把钥匙,指向同一间房子------不管谁进去装修,另一个人看到的也是装修后的样子。

五、从内存角度看,一切就更清晰了

如果你还想再深入一点,我们来聊聊内存。别怕,用个比喻帮你说清楚。

5.1 计算机的"工作台"

回到计算机的祖师爷------冯·诺依曼体系。市面上几乎所有计算设备(你的手机、笔记本、台式机)都遵循这个架构:

复制代码
运算器 + 控制器 + 存储器 + 输入设备 + 输出设备

你的代码躺在硬盘(外存)里 → 运行的时候加载到内存 → CPU 去内存里取指令、算数据。

5.2 栈内存 vs 堆内存

JS 引擎在执行代码时,会创建执行上下文 (你可以理解为"当前代码的运行环境快照"),包含变量环境、词法环境,然后把它推入调用栈

  • 栈内存 :快,但是空间小。存的是原始数据类型的值本身 ,以及引用数据类型的地址(门牌号)。函数执行上下文占多大空间在编译阶段就能算出来,分配得刚刚好。函数执行完、出栈,指针一偏就切到下一个上下文了------快速、稳定。
  • 堆内存 :大,但是慢。存的是对象本身的数据。为什么对象不放栈里?因为对象可能很大、可能动态增删属性,大小没法在编译时确定,只能放到"随便长"的堆里。

这就完美解释了:

  • 原始类型赋值 = 复印:值直接存在栈里,拷贝就是复制一份值
  • 引用类型赋值 = 共享地址:栈里存的只是堆内存的门牌号,拷贝的是门牌号,不是房子

六、一张图总结

类型

分类

赋值方式

一句话

Number

原始

拷贝值

存数字,小数偶尔会不精确

String

原始

拷贝值

存文本

Boolean

原始

拷贝值

只有 true / false

null

原始

拷贝值

主动清空,表示"故意没有"

undefined

原始

拷贝值

被动缺失,表示"该来的没来"

Symbol

原始

拷贝值

独一无二的标识符

BigInt

原始

拷贝值

超大整数精确计算

Object

引用

拷贝地址

所有对象的祖宗,传地址不传值

写在最后

JavaScript 的数据类型是地基。地基不牢,后面学原型链、闭包、异步这些东西就容易塌。强烈建议你打开浏览器控制台,把文中的例子一个个敲一遍,亲手感受 nullundefined 的区别、Symbol() 的唯一性、BigInt 的精度------动手永远是最好的学习方式

源码文件就在这个 type 目录下,每个 .js 文件对应一个独立的知识点,注释写得清晰明了,配合这篇文章一起看,效果更好 🚀

相关推荐
心之所向vjuif1 小时前
使用 Gemini 解决前端代码报错问题
前端
数据知道1 小时前
视觉伪装(上):Canvas 指纹生成原理与 Skia 图形库底层注入噪声
开发语言·javascript·ecmascript·数据采集·指纹浏览器
文阿花1 小时前
Echarts实现自定旋转3D饼状图
javascript·3d·echarts·饼状图
San813_LDD2 小时前
[深度学习] 数据序列化格式对比:以日志级别配置为例
xml·java·前端
meilindehuzi_a2 小时前
深入理解 JavaScript 的同步与异步机制:从单线程设计到 Promise 核心应用
开发语言·javascript·ecmascript
如烟花的信页2 小时前
加速乐cookie逆向分析
javascript·爬虫·python·js逆向
永远的WEB小白2 小时前
css改变svg图标的颜色
前端·javascript·css
lfwh2 小时前
探针程序技术解析:基于 Spring Boot 非 Web 模式的云服务监控告警系统
前端·spring boot·后端
Ajie'Blog2 小时前
AI 周报 | Claude Opus 4.8、Copilot Agent 和 Codex 工作流加速
前端·人工智能·gpt·ai·copilot·ai编程