JavaScript 的数据类型主要分为两大类:原始类型(Primitive types)和对象类型(Object types)。 以下是它们的详细分类和区别:
一、原始类型(Primitive types)
-
Number
- 表示整数和浮点数
- 特殊值:
NaN(非数字)、Infinity(无穷大) - 例如:
42,3.14
-
String
- 表示文本数据
- 可以用单引号、双引号或反引号(模板字符串)定义
- 例如:
"hello",'world',`hi ${name}`
-
Boolean
- 逻辑值:
true或false - 用于条件判断
- 逻辑值:
-
Null
- 表示"无"或"空"的故意赋值
- 类型(typeof)为
object(历史遗留问题)
-
Undefined
- 表示变量已声明但未赋值/未定义的变量
- 函数无返回值时默认返回
undefined
-
Symbol(ES6新增)
- 表示唯一标识符,创建后独一无二且不可变,主要是为了解决可能出现的全局变量冲突的问题
- 用于创建对象的唯一属性键
- 例如:
const id = Symbol('id')
-
BigInt(ES2020新增)
- 表示任意精度的整数,是一种数字类型的数据,可以安全地存储和操作大整数
- 用于超出
Number安全范围的数值 - 例如:
9007199254740991**n**
二、对象类型(Object types)
-
Object
- 键值对的集合
- 包括:普通对象、数组、日期、正则表达式等
- 例如:
{name: 'Alice'},[1,2,3]
-
Function
- 可执行对象
- 实际是
object的子类型
三、主要区别
| 特性 | 原始类型 | 对象类型 |
|---|---|---|
| 存储方式 | 按值存储 | 按引用存储(指针) |
| 可变性 | 不可变(值本身) | 可变(属性可修改) |
| 比较方式 | 值比较 | 引用比较 |
| 内存分配 | 栈内存(stack),生命周期由作用域控制 | 堆内存(heap),通过垃圾回收机制(GC)管理 |
| 方法调用 | 自动装箱为临时对象 | 直接调用 |
| 占据空间 | 占据空间小、大小固定 | 占据空间大、大小不固 |
四、其他
- 包装对象(Wrapper Object)
- 原始类型可临时转为对象以调用方法:
const str = "hello";
console.log(str.toUpperCase()); // "HELLO"(自动创建临时 String 对象)
- 类型转换
- 显式转换:String(), Number(), Boolean()。
- 隐式转换:== 运算符触发类型转换:
'5' == 5; // true(字符串转数字)
null == undefined; // true
- 对象拆箱(Unboxing) 对象在运算时会被转换为原始值:
const obj = {
valueOf: () => 42,
toString: () => '100'
};
console.log(obj + 1); // 43(优先调用 valueOf)
五、最佳实践
- 优先使用 ===:避免隐式类型转换带来的意外。
- 深拷贝对象:使用 JSON.parse(JSON.stringify(obj)) 或工具库(如 Lodash 的 _.cloneDeep)。
- 处理 null 和 undefined:使用可选链操作符(?.)或空值合并运算符(??)。
六、小知识
- 在数据结构中:
- 栈中数据的存取方式为先进后出。
- 堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。
- 在操作系统中,内存被分为栈区和堆区:
- 栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
- 堆区内存一般由开发着分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。