学 JavaScript 数据类型,真正要搞懂的是:变量里存的到底是什么?

学 JavaScript 数据类型,真正要搞懂的是:变量里存的到底是什么?

最近复习了 JavaScript 的数据类型、nullundefined、堆栈内存、BigIntSymbol。这些知识看起来很基础,但它们决定了我们能不能真正理解赋值、对象修改、精度问题和垃圾回收。

前言

刚开始学 JavaScript 数据类型时,很容易只停留在背概念:

txt 复制代码
Number、String、Boolean、null、undefined、Symbol、BigInt、Object

但真正写代码时,问题往往不是"JS 有几种类型",而是:

txt 复制代码
为什么改了 obj2,obj1 也变了?
为什么 0.1 + 0.2 不等于 0.3?
null 和 undefined 到底怎么区分?
为什么 Symbol("a") 不等于 Symbol("a")?

这些问题背后,其实都指向同一件事:变量里保存的到底是什么。

JavaScript 有哪些数据类型?

JavaScript 数据类型可以分成两大类:

  • 原始类型
  • 引用类型

原始类型有 7 种:

txt 复制代码
Number
String
Boolean
null
undefined
Symbol
BigInt

引用类型主要是:

txt 复制代码
Object

数组、函数、日期、正则,本质上也都属于对象类型的不同形式。

所以可以简单记成:

txt 复制代码
7 种原始类型 + 1 种引用类型 = 8 种数据类型

原始类型:赋值拷贝的是值

先看一个简单例子:

js 复制代码
let a = null;
let b = a;

b = 2;

console.log(a); // null
console.log(b); // 2

这里 b = a 的意思是,把 a 里面保存的值复制一份给 b

后面修改 b,不会影响 a

这就是原始类型的特点:

txt 复制代码
赋值时,拷贝的是值本身。

类似 NumberStringBooleannullundefinedSymbolBigInt 都可以先这样理解。

引用类型:赋值拷贝的是地址

再看对象:

js 复制代码
let obj1 = { name: "雷神" };
let obj2 = obj1;

obj2.company = "快手";

console.log(obj1);
console.log(obj2);

你会发现,obj1 里面也出现了 company

原因是:

js 复制代码
let obj2 = obj1;

这行代码并没有复制一个新对象,而是复制了对象的引用地址。

也就是说,obj1obj2 指向的是同一个对象。

可以这样理解:

txt 复制代码
obj1 里保存一个地址
obj2 拷贝了这个地址
两个变量通过同一个地址找到同一个对象

所以修改其中一个变量指向的对象,另一个变量也能看到变化。

这就是引用类型和原始类型最关键的区别。

null:我主动告诉你这里是空

null 通常表示"这里本来可以有值,但现在明确为空"。

比如:

js 复制代码
let user = {
  name: "Alice",
  address: null
};

console.log(user.address); // null

这里的 address: null 表达的是:这个字段存在,只是目前没有地址。

再比如手动解除引用:

js 复制代码
let largeObject = {
  data: new Array(10).fill("hgh")
};

largeObject = null;

这表示变量 largeObject 不再指向原来的对象。

注意,这不是立即释放内存,而是让原来的对象有机会被垃圾回收机制回收。

undefined:系统告诉你这里还没有值

undefined 更像是系统给出的默认结果。

常见场景有几个。

声明变量但没有赋值:

js 复制代码
let a;

console.log(a); // undefined

访问不存在的对象属性:

js 复制代码
let obj = {};

console.log(obj.age); // undefined

函数没有返回值:

js 复制代码
function noReturn() {}

console.log(noReturn()); // undefined

访问不存在的数组索引:

js 复制代码
let arr = [1, 2, 3];

console.log(arr[5]); // undefined

可以简单区分:

txt 复制代码
null:我主动设置为空
undefined:系统发现这里没有值

这句话对初学阶段很有用。

栈内存和堆内存:变量保存在哪里?

理解原始类型和引用类型,还需要一点内存模型。

可以先建立一个简化版本:

txt 复制代码
栈内存:存基本值、引用地址、函数执行上下文
堆内存:存对象、数组、函数等复杂数据

比如:

js 复制代码
let num = 1;
let obj = { name: "Alice" };

可以粗略理解为:

  • num 的值 1 直接放在栈里
  • obj 变量里保存的是一个地址
  • 真正的 { name: "Alice" } 对象放在堆里

这也解释了为什么对象赋值后会互相影响。

因为两个变量保存了同一个堆内存地址。

Number:为什么 0.1 + 0.2 不等于 0.3?

看这段代码:

js 复制代码
let a = 0.1;
let b = 0.2;

console.log(a + b);

结果不是精确的 0.3,而是:

txt 复制代码
0.30000000000000004

原因是计算机底层用二进制表示数字,而有些十进制小数无法被二进制精确表示。

这不是 JavaScript 独有的问题,很多语言都有类似现象。

在金额计算、精度要求高的场景里,不能直接依赖浮点数做精确计算。

BigInt:用来处理大整数

普通 Number 有安全整数范围。如果数字特别大,就需要 BigInt

写法是在整数后面加 n

js 复制代码
let num1 = 999999999999999999999999999999999999999n;
let num2 = 123456789098765433467324577654789008733n;

console.log(num1 + num2);
console.log(typeof num1); // bigint

需要注意的是,BigInt 不能随便和普通 Number 混用。

正确:

js 复制代码
console.log(num1 + 1n);

不推荐直接这样混:

js 复制代码
// TypeError
console.log(num1 + 1);

如果要一起运算,需要先明确转换类型。

Symbol:每次创建都是唯一的

Symbol 用来创建唯一值。

即使描述文字一样,两个 Symbol 也不相等:

js 复制代码
console.log(Symbol("雷神") === Symbol("雷神")); // false
console.log(typeof Symbol("雷神")); // symbol

Symbol("雷神") 里的 "雷神" 只是描述,不参与相等判断。

它常用于创建不容易冲突的对象属性:

js 复制代码
let obj = {
  [Symbol()]: "value",
  prop: "2"
};

普通对象属性名很容易重复,但 Symbol 创建出来的属性键是唯一的。

小结

这次复习 JS 数据类型,最重要的不是背名字,而是理解变量里保存的内容。

核心点可以压缩成几句话:

  • JS 有 7 种原始类型和 1 种引用类型
  • 原始类型赋值拷贝值
  • 引用类型赋值拷贝地址
  • null 是主动设置为空
  • undefined 通常表示还没有值
  • 栈内存保存基本值和引用地址
  • 堆内存保存对象、数组、函数等复杂数据
  • Number 存在浮点数精度问题
  • BigInt 适合处理大整数
  • Symbol 用来创建唯一标识

最后,用一句话总结:

txt 复制代码
学 JS 数据类型,不只是学类型名字,而是学变量和值之间的关系。

理解了这个关系,再去看浅拷贝、深拷贝、垃圾回收、类型判断和隐式转换,就会顺很多。

相关推荐
ZengLiangYi1 小时前
测试策略:单元测试 + 集成测试怎么写
javascript·typescript·node.js
JieE2121 小时前
JS 到底有多少种数据类型?从ECMA规范到内存本质,一文彻底搞懂
javascript·数据结构·面试
前端Hardy2 小时前
GitHub 爆火!Three.js + React + ECharts 打造最强数据大屏
前端·javascript
数据知道2 小时前
视觉伪装(下):WebGL 渲染器与厂商特征的底层伪造与屏蔽
javascript·数据采集·webgl·指纹浏览器
东风破_3 小时前
JS 数据类型:从八种分类到栈与堆的内存真相
javascript
YIAN3 小时前
# 从入门到封装:一文搞懂 Fetch API 所有用法(新手友好)
前端·javascript
xiaofeichaichai3 小时前
Tree Shaking
前端·javascript
Darling噜啦啦4 小时前
JavaScript 数组深度解析:从纯函数到二维数组陷阱,一文吃透前端数据结构核心
前端·javascript·数据结构
万少4 小时前
一封邮件,让我重新打开了搁置半年的鸿蒙应用
前端·javascript·后端