Appearance
JavaScript 数据类型详解
导航目录
- 数据类型种类
- typeof 关键字
- typeof null 等于 object 的原因
- null 和 undefined 区别
- 引用类型特性
- 内存管理机制
- var, let, const 对比
- 暂时性死区 (TDZ)
数据类型种类
TIP
JavaScript 中有 8 种数据类型,分为基本数据类型和引用数据类型两大类
基本数据类型
基本数据类型是不可变的值,直接存储在栈内存中:
String:字符串类型,如"Hello"Number:数值类型,如42或3.14Boolean:布尔类型,值为true或falseNull:表示空对象指针,值为nullUndefined:表示未初始化的值,值为undefinedSymbol:唯一标识符,ES6 新增BigInt:大整数类型,ES11 新增,用于表示超出 Number 范围的整数
引用数据类型
引用数据类型是可变的对象,存储在堆内存中,栈中保存的是指向堆内存的引用:
Object(包含多种形式):- 普通对象:
{} - 数组:
[] - 正则表达式:
/^$/ - 日期对象:
new Date() - 数学对象:
Math - 函数:
function() {}
- 普通对象:
typeof 关键字
typeof 是 JavaScript 中用于检测数据类型的操作符,它总是返回字符串类型的值,表示被检测值的类型:
- 检测结果示例:
js
typeof a; // "undefined" (未声明变量)
typeof 1; // "number"
typeof NaN; // "number" (特殊数值)
typeof "zhufeng"; // "string"
typeof true; // "boolean"
typeof Symbol("a"); // "symbol"
typeof function () {}; // "function"
typeof [1, 2, 3]; // "object" (数组)
typeof { name: "zhufeng" }; // "object" (普通对象)
typeof new Number(1); // "object" (包装对象)
typeof null; // "object" (历史遗留问题)typeof null 等于 object 的原因
js
typeof null; // "object"原因分析
- 历史遗留问题:JavaScript 早期设计中,所有值都用 32 位表示,其中前 3 位为类型标签。
null的类型标签被错误地设置为与对象相同的标签(000) - 无法修复:修复会破坏大量现有程序和库的兼容性,因此成为 JavaScript 的一个设计缺陷
- 正确检测方法:使用严格相等运算符
===来检测nulljsconst isNull = (value) => value === null;
null 和 undefined 区别
| 特性 | null | undefined |
|---|---|---|
| 含义 | 空对象指针 | 未初始化的值 |
| 类型 | object | undefined |
| 数值转换 | 转换为 0 (+null → 0) | 转换为 NaN (+undefined → NaN) |
| 使用场景 | 主动赋空值 | 变量声明未赋值 |
示例代码
js
// 使用场景
var a; // undefined (未初始化)
var b = null; // null (显式赋空值)
// 数值转换差异
console.log(10 + null); // 10 (null → 0)
console.log(10 + undefined); // NaN (undefined → NaN)引用类型特性
核心特性
引用类型变量存储的是内存地址引用而非实际值,多个变量引用同一对象时,修改会相互影响
示例代码
js
// 引用类型示例
let person = { username: "hulei" };
let employee = person;
employee.age = 20; // 通过引用修改对象
console.log(person); // {username: "hulei", age: 20}
console.log(employee === person); // true (相同引用)
内存管理机制
JavaScript 使用自动内存管理,通过垃圾回收机制来管理内存。了解内存存储机制有助于理解数据类型的行为。
内存区域对比
| 特性 | 栈 (Stack) | 堆 (Heap) |
|---|---|---|
| 结构 | 线性有序存储 | 非线性动态分配 |
| 访问速度 | 高速访问 | 相对较慢 |
| 存储内容 | 基本类型值/对象引用指针 | 对象实际数据 |
| 生命周期 | 随函数执行结束自动释放 | 由垃圾回收机制管理 |
存储规则
- 基本类型:值直接存储在栈内存中,占用空间小,访问速度快
- 引用类型:对象数据存储在堆中,栈中存储指向堆内存的指针,占用空间较大
示例代码
js
// 基本类型 - 栈存储
let num = 10; // 值直接存储在栈中
// 引用类型 - 堆存储
let obj = { value: 10 }; // 对象存储在堆中,栈中存储引用地址var, let, const 对比
| 特性 | var | let | const |
|---|---|---|---|
| 作用域 | 函数作用域 | 块级作用域 | 块级作用域 |
| 重复声明 | ✓ 允许 | ✗ 禁止 | ✗ 禁止 |
| 变量提升 | ✓ 存在 | ✗ 不存在 | ✗ 不存在 |
| 全局属性 | 成为 window 属性 | 不成为 | 不成为 |
| 重新赋值 | ✓ 允许 | ✓ 允许 | ✗ 禁止(对象属性可修改) |
示例代码
js
// var 的典型问题
for (var i = 0; i <= 5; i++) {
console.log(i);
}
console.log(i); // 6 (变量泄漏到全局)
// let/const 的块级作用域解决方案
for (let j = 0; j <= 5; j++) {
console.log(j);
}
console.log(j); // ReferenceError: j未定义暂时性死区 (TDZ)
核心概念
- 定义:从代码块开始到变量声明完成之间的区域
- 表现:此区域内访问变量会抛出
ReferenceError - 机制:变量在声明语句执行时才被初始化
示例代码
js
// var 允许声明前访问
console.log(a); // undefined
var a = 10;
// let/const 存在暂时性死区
{
console.log(b); // ReferenceError: 无法在初始化前访问b
let b = 20;
}TDZ 规则详解
- 进入块作用域时立即创建 TDZ
- 执行到声明语句时才初始化变量
- 访问 TDZ 变量抛出
ReferenceError typeof检测 TDZ 变量也会报错
示例代码
js
{
// TDZ开始
typeof tmp; // ❌ ReferenceError
let tmp; // TDZ结束
console.log(tmp); // undefined
}