JavaScript 数据类型
两大分类
- 基本类型(Primitive Types):
string:字符串number:数字boolean:布尔值null:空值undefined:未定义symbol(ES6新增):符号,表示唯一值bigint(ES2020新增):大整数,表示任意大的整数
- 引用类型(Reference Types):
Object:对象- 包括:
Array,Function,Date,RegExp,Map,Set,WeakMap,WeakSet等。
基本类型 vs 引用类型的核心区别
| 特性 | 基本类型 | 引用类型 |
|---|---|---|
| 存储方式 | 栈内存(直接存储值) | 堆内存(存储地址,栈中存指针) |
| 赋值行为 | 复制值(新旧变量互不影响) | 复制指针(指向同一内存对象) |
| 比较方式 | 值比较('a' === 'a' → true) |
引用比较({} === {} → false) |
| 函数传参 | 传递值的副本 | 传递指针副本(内部修改影响外部对象) |
| 动态属性 | 不可添加属性 | 可动态添加/删除属性 |
| 内存管理 | 变量销毁时自动回收 | 需垃圾回收机制处理 |
复习一下数据结构:
1.栈(Stack)
逻辑结构:一种线性结构,遵循后进先出(LIFO)原则,仅允许在表的一端(栈顶)进行插入(push)和删除(pop)操作。
物理实现:通常通过数组或链表实现,数据连续存储,操作仅涉及栈顶元素。
典型操作:
push:将元素压入栈顶。
pop:弹出栈顶元素。
peek:查看栈顶元素(不弹出)。
2.堆(Heap)
逻辑结构:一种树形结构,通常为完全二叉树,满足堆性质(父节点的值大于或等于子节点的值称为最大堆,反之为最小堆)。
物理实现:通过数组实现,逻辑上模拟树结构,物理上连续存储。
典型操作:
insert:插入元素并保持堆性质。
extract:移除根节点(最大或最小值)。
heapify:调整节点位置以维护堆性质。
示例说明
1 | // 基本类型 - 值复制 |
Symbol 详解
作用:创建唯一的、不可变的值,常用作对象属性的键(避免命名冲突)。
特性:
- 通过
Symbol([description])创建 - 即使描述相同,Symbol 值也不同:
Symbol('id') !== Symbol('id') - 不可枚举(
for...in跳过),需用Object.getOwnPropertySymbols()获取1
2
3const sym1 = Symbol('id');
const sym2 = Symbol('id');
console.log(sym1 === sym2); // false(唯一性)
应用场景:
唯一对象属性键
避免第三方库属性名冲突:1
2
3
4const user = {
name: "Alice",
[Symbol('id')]: 123 // 隐藏属性
};模拟私有属性
(需配合Object.defineProperty或闭包实现真正私有):1
2
3
4
5
6const _password = Symbol('password');
class User {
constructor(password) {
this[_password] = password;
}
}全局 Symbol 注册表
跨模块共享 Symbol:1
2
3
4
5// module1.js
const id = Symbol.for('global_id');
// module2.js
const sameId = Symbol.for('global_id');
console.log(id === sameId); // true内置 Symbol 值
定制对象行为(如迭代器):1
2
3
4
5
6
7const obj = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
}
};
console.log([...obj]); // [1, 2]
应用场景
| 场景 | 说明 | 示例 |
|---|---|---|
| 唯一对象属性键 | 由于Symbol值是唯一的,因此可以用来作为对象属性的键,避免属性名冲突 | const obj = { [Symbol('id')]: 123 }; |
| 模拟私有属性 | 配合闭包实现伪私有属性(虽然ES6的类并没有真正的私有属性,但使用Symbol可以在一定程度上模拟私有属性,因为外部无法直接访问Symbol属性) | const _key = Symbol(); class Safe { constructor(k) { this[_key] = k; } } |
| 全局Symbol注册表 | 跨模块/文件共享Symbol | //module1.js Symbol.for('global'); //module2.js Symbol.for('global'); |
| 内置Symbol行为定制 | 实现迭代协议等特殊行为(ES6提供了一些内置的Symbol值,用于改变语言内部行为,如Symbol.iterator(定义迭代器)、Symbol.toStringTag) |
const iterable = { [Symbol.iterator]: function*() { yield 1; } }; |
| 定义常量 | 用于定义一组常量,保证这组常量的值都是不相等的。 | const LOG_LEVEL = {DEBUG: Symbol('debug'),INFO: Symbol('info'),ERROR: Symbol('error')}; |
BigInt 详解
特性
作用:表示任意精度的整数,解决 Number 类型无法安全表示的大整数问题(Number.MAX_SAFE_INTEGER = 2^53 - 1)。
特性:
- 字面量加
n后缀:12345678901234567890n - 通过
BigInt()函数转换:BigInt("9007199254740993") - 不能与
Number直接运算(需显式转换)
应用场景:
大整数运算
金融、科学计算等需要高精度的场景:1
2
3const big1 = 9007199254740993n;
const big2 = 1n;
console.log(big1 + big2); // 9007199254740994n大 ID 处理
数据库返回的 64 位 ID(如 Snowflake 算法生成的 ID):1
const id = BigInt("12345678901234567890"); // 超出 Number 安全范围
高精度时间戳
纳秒级时间戳运算:1
2
3
4const start = process.hrtime.bigint(); // Node.js
// 执行操作...
const end = process.hrtime.bigint();
console.log(`耗时: ${(end - start) / 1000000n} 毫秒`);大数加密/哈希
密码学中的大整数运算:1
const prime = BigInt("0xFFFFFFFFFFFFFFFFC90FDAA...");
注意事项:
- 不支持
Math对象的方法 - 与
Number比较时类型不同(1n === 1→false) - JSON 序列化需自定义处理(默认抛出错误)
1 | // 类型转换 |
总结对比
| 类型 | 核心特性 | 典型应用场景 |
|---|---|---|
Symbol |
唯一性、不可枚举、避免冲突 | 对象元编程、私有属性模拟、库开发 |
BigInt |
任意精度、突破Number安全限制 |
大整数ID、金融计算、高精度时间处理 |