JavaScript 数据类型全景图:从基础到进阶

🧱 JavaScript 数据类型全景图:从基础到进阶

很多初学者认为 JS 只有"字符串"和"数字",或者分不清 nullundefined 的区别。

其实,JS 的数据类型设计非常精巧,分为两大阵营:基本数据类型(值类型)引用数据类型

理解它们的区别,就理解了 JS 内存管理的核心。

📂 目录

  1. [🗺️ 两大阵营:基本类型 vs 引用类型](#🗺️ 两大阵营:基本类型 vs 引用类型)
  2. [📦 8 种数据类型详解](#📦 8 种数据类型详解)
  3. [🧠 核心差异:栈内存 vs 堆内存](#🧠 核心差异:栈内存 vs 堆内存)
  4. [🔍 如何准确判断数据类型?](#🔍 如何准确判断数据类型?)
  5. [⚠️ 常见面试题与坑点](#⚠️ 常见面试题与坑点)
  6. [💡 总结](#💡 总结)

1. 🗺️ 两大阵营:基本类型 vs 引用类型

JavaScript 共有 8 种 数据类型(ES6 新增 Symbol,ES10 新增 BigInt)。它们被分为两类:

✅ 基本数据类型(Primitive Types)

存储在**栈(Stack)**中,直接存储值。

  1. String(字符串)
  2. Number(数字)
  3. Boolean(布尔值)
  4. Undefined(未定义)
  5. Null(空对象指针)
  6. Symbol(符号,ES6 新增)
  7. BigInt(大整数,ES10 新增)

✅ 引用数据类型(Reference Types)

存储在堆(Heap)中,栈中只存储指向堆内存的地址(指针) 。8. Object(对象)

  • 包括:Array(数组)、Function(函数)、Date(日期)、RegExp(正则)等。

注意 :虽然 FunctionArray 很特殊,但在 typeof 检测时,它们都属于 object 的子集(除了 Function 返回 'function')。


2. 📦 8 种数据类型详解

1. String(字符串)

用于表示文本数据。

javascript 复制代码
const name = "Lingma";
const greeting = "Hello World";
const template = `Hi, ${name}`; // 模板字符串

2. Number(数字)

包括整数和浮点数。还有一个特殊的 NaN (Not a Number)。

javascript 复制代码
const age = 25;
const price = 9.99;
const notNum = NaN;
console.log(NaN === NaN); // false! NaN 不等于任何值,包括它自己

3. Boolean(布尔值)

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

javascript 复制代码
const isReady = true;
const isEmpty = false;

4. Undefined(未定义)

声明了变量但未赋值,或者对象中不存在的属性。

javascript 复制代码
let a;
console.log(a); // undefined

const obj = {};
console.log(obj.name); // undefined

5. Null(空)

表示"空值"或"无对象"。它是一个赋值值,通常用于初始化一个将来要存放对象的变量。

javascript 复制代码
let user = null; // 明确表示当前没有用户对象

6. Symbol(符号)

ES6 引入,创建唯一的值。常用于作为对象属性的键,防止属性名冲突。

javascript 复制代码
const id1 = Symbol("id");
const id2 = Symbol("id");
console.log(id1 === id2); // false,即使描述相同,它们也是唯一的

7. BigInt(大整数)

ES10 引入,用于表示超过 Number 安全范围(2^53 - 1)的整数。

javascript 复制代码
const bigNum = 9007199254740991n;
const anotherBig = BigInt(9007199254740991);

8. Object(对象)

键值对的集合。

javascript 复制代码
const person = {
  name: "Lingma",
  age: 25,
  sayHi: function () {
    console.log("Hi");
  },
};

const list = [1, 2, 3]; // 数组也是对象

3. 🧠 核心差异:栈内存 vs 堆内存

这是理解 JS 赋值和拷贝的关键!

📌 基本类型:按值访问

  • 存储 :直接存储在栈内存中。
  • 拷贝 :赋值时,会创建一个全新的副本。修改其中一个,不影响另一个。
javascript 复制代码
let a = 10;
let b = a; // b 复制了 a 的值
b = 20;
console.log(a); // 10 (a 不受影响)

📌 引用类型:按引用访问

  • 存储 :实际数据存储在堆内存中,栈内存中只存一个**指针(地址)**指向堆。
  • 拷贝 :赋值时,复制的是指针。两个变量指向同一个堆内存对象。修改其中一个,另一个也会变。
javascript 复制代码
let obj1 = { name: "Lingma" };
let obj2 = obj1; // obj2 复制了指针,指向同一个对象
obj2.name = "Aliyun";
console.log(obj1.name); // "Aliyun" (obj1 也被改变了!)

比喻

  • 基本类型就像你有一张现金,给朋友一张复印件(假设能复印),他花他的,你的还在。
  • 引用类型就像你有一个保险箱(堆),你把保险箱的钥匙(指针)复制了一把给朋友。朋友用钥匙打开保险箱改了里面的东西,你再去开,发现东西也变了。

4. 🔍 如何准确判断数据类型?

JS 提供了多种检测手段,但各有优劣。

1. typeof 操作符

最常用,适合检测基本类型函数

javascript 复制代码
typeof 100; // "number"
typeof "Hello"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof Symbol(); // "symbol"
typeof 10n; // "bigint"
typeof function () {}; // "function"
typeof {}; // "object" ⚠️ 陷阱
typeof []; // "object" ⚠️ 陷阱
typeof null; // "object" ⚠️ 历史遗留 Bug

缺点 :无法区分 nullArray 和普通 Object,它们都返回 "object"

2. instanceof 操作符

用于检测引用类型的原型链。

javascript 复制代码
[] instanceof Array;   // true
{} instanceof Object;  // true
new Date() instanceof Date; // true

缺点:不能检测基本类型;在不同 iframe 或窗口间可能失效(因为原型链不同)。

3. Object.prototype.toString.call()推荐万能方法

这是最准确、最通用的检测方式。

javascript 复制代码
const typeCheck = (val) => Object.prototype.toString.call(val);

typeCheck(100); // "[object Number]"
typeCheck("Hello"); // "[object String]"
typeCheck(null); // "[object Null]"
typeCheck(undefined); // "[object Undefined]"
typeCheck([]); // "[object Array]"
typeCheck({}); // "[object Object]"
typeCheck(new Date()); // "[object Date]"

封装一个通用工具函数:

javascript 复制代码
function getType(val) {
  return Object.prototype.toString.call(val).slice(8, -1).toLowerCase();
}

console.log(getType([])); // "array"
console.log(getType(null)); // "null"
console.log(getType(function () {})); // "function"

5. ⚠️ 常见面试题与坑点

❓ 问题 1:nullundefined 的区别?

特性 undefined null
含义 "缺少值",未初始化 "空值",有意为空
来源 变量声明未赋值、函数无返回值、对象属性不存在 手动赋值,表示对象为空
类型转换 Number(undefined) -> NaN Number(null) -> 0
最佳实践 让 JS 引擎自动处理 开发者主动赋值为 null 以释放引用或初始化

❓ 问题 2:为什么 typeof null"object"

这是一个著名的 JS 历史 Bug

在 JS 最初版本中,值存储在 32 位单元中,低 3 位用于存储类型标签。

  • 000 代表对象。
  • null 的全是 0,所以低 3 位也是 000,被误判为对象。
    为了兼容性,这个 Bug 一直保留至今。

❓ 问题 3:0.1 + 0.2 === 0.3 吗?

答案是 false

javascript 复制代码
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false

原因 :JS 使用 IEEE 754 双精度浮点数标准,二进制无法精确表示 0.1 和 0.2,导致精度丢失。
解决 :使用误差范围比较,或使用库如 decimal.js


💡 总结

类型 存储位置 拷贝方式 典型检测
基本类型 栈 (Stack) 值拷贝 (深拷贝效果) typeof
引用类型 堆 (Heap) 引用拷贝 (浅拷贝) instanceof / toString

🚀 博主寄语

数据类型是 JS 的根基。
记住三个重点

  1. 基本类型存值,引用类型存地址。
  2. typeof null"object" 是历史遗留问题。
  3. 想要精准判断类型,请用 Object.prototype.toString.call()

掌握了这些,你就迈出了成为高级前端工程师坚实的一步!

希望这篇文档能帮你彻底理清 JS 数据类型!如果有疑问,欢迎在评论区留言。👇

喜欢这篇文章吗?记得点赞、收藏、转发哦! ❤️

相关推荐
JieE21210 小时前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
冬奇Lab12 小时前
AI Workflow 定义的四次演进:从 Markdown 到 JS 脚本,再到分布式多 Agent
javascript·人工智能·agent
一颗烂土豆17 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
kyriewen20 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
weedsfly1 天前
迭代器、生成器与异步迭代——让数据“按需流动”的艺术
前端·javascript
假如让我当三天老蒯1 天前
前端跨域解决方案(学习用)
前端·javascript·面试
铁皮饭盒1 天前
Bun 哪比 Node.js 快?
javascript·后端
JieE2121 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
candyTong1 天前
RTK 技术原理:一次典型会话里,80% 上下文是怎么省下来的
javascript·后端·架构
_柳青杨2 天前
深入理解 JavaScript 事件循环
前端·javascript