🧱 JavaScript 的基石:彻底搞懂 8 种数据类型
🤔 为什么需要区分数据类型?
在 JavaScript 中,数据分为两大类:基本数据类型(Primitive)和引用数据类型(Reference)。
通俗比喻:
想象你在整理房间(内存):
- 基本类型就像便签纸。你把名字、年龄直接写在便签上,随身携带。复制便签时,是把内容抄写一份新的,两张便签互不影响。
- 引用类型就像储物柜钥匙。对象太大,不能随身带,所以存在储物柜(堆内存)里,你手里只拿一把钥匙(栈内存中的地址)。复制钥匙时,只是多了一把能开同一个柜子的钥匙。如果一个人改了柜子里的东西,另一个人看到的也变了。
理解这一点,是解决“变量赋值后互相影响”、“深拷贝/浅拷贝”等问题的关键。
📂 目录
- 📋 全家福:JS 的 8 种数据类型
- 🧠 核心区别:栈内存 vs 堆内存
- 🔍 检测神器:typeof 与 instanceof
- ⚠️ 常见坑点与面试题
- 💻 实战技巧:类型转换与判断
- 💡 总结
1. 📋 全家福:JS 的 8 种数据类型
ES6 之前有 6 种,ES6 新增了Symbol,ES10 (ES2020) 新增了BigInt。目前共有8 种。
✅ 7 种基本数据类型(Primitive)
存储在栈(Stack)中,按值访问。
| 类型 | 英文 | 说明 | 示例 |
|---|---|---|---|
| Number | 数字 | 整数、浮点数、NaN、Infinity | 1,3.14,NaN |
| String | 字符串 | 文本数据 | "Hello",'World' |
| Boolean | 布尔值 | 逻辑真/假 | true,false |
| Undefined | 未定义 | 声明了但未赋值 | let a; console.log(a) |
| Null | 空对象指针 | 表示“无”的对象值 | null |
| Symbol | 符号 | ES6 新增,唯一且不可变的标识 | Symbol('id') |
| BigInt | 大整数 | ES10 新增,用于超大整数运算 | 123n |
✅ 1 种引用数据类型(Reference)
存储在堆(Heap)中,按引用(地址)访问。
| 类型 | 英文 | 说明 | 示例 |
|---|---|---|---|
| Object | 对象 | 键值对集合,包括数组、函数、正则等 | {},[],function(){} |
注意:虽然
Array、Function、Date看起来不同,但它们在typeof检测下都属于object(Function 除外,见下文),本质都是 Object 的子类。
2. 🧠 核心区别:栈内存 vs 堆内存
这是理解 JS 类型最核心的部分。
🔹 基本类型:值传递
leta=10;letb=a;// 把 10 复制一份给 ba=20;// 修改 aconsole.log(a);// 20console.log(b);// 10 <-- b 不受影响- 内存表现:栈中开辟两个独立空间,互不干扰。
🔹 引用类型:引用传递
letobj1={name:"Alice"};letobj2=obj1;// 把地址复制给 obj2,指向同一个堆内存对象obj1.name="Bob";// 修改堆内存中的数据console.log(obj1.name);// "Bob"console.log(obj2.name);// "Bob" <-- obj2 也变了!- 内存表现:栈中存储的是地址指针,堆中存储实际数据。复制的是指针,所以指向同一块数据。
3. 🔍 检测神器:typeof 与 instanceof
✅typeof操作符
用于检测基本类型,返回一个字符串。
typeof10;// "number"typeof"Hello";// "string"typeoftrue;// "boolean"typeofundefined;// "undefined"typeofSymbol();// "symbol"typeof123n;// "bigint"typeoffunction(){};// "function" <-- 特例typeof{};// "object"typeof[];// "object" <-- 注意:数组也是 objecttypeofnull;// "object" <-- 历史遗留 Bug!⚠️ 重点记忆:
typeof null === 'object'是 JS 早期的设计失误,为了兼容旧代码一直保留至今。typeof无法区分数组、普通对象、日期等,它们都返回'object'。
✅instanceof操作符
用于检测引用类型,判断对象的原型链上是否有构造函数的prototype。
[]instanceofArray;// true{}instanceofObject;// truenewDate()instanceofDate;// true注意:
instanceof只能用于对象,不能用于基本类型(除非装箱,但不推荐)。
✅ 终极检测:Object.prototype.toString.call()
如果需要精准判断所有类型(包括 Array、Null、Date 等),这是最可靠的方法。
Object.prototype.toString.call(10);// "[object Number]"Object.prototype.toString.call("Hello");// "[object String]"Object.prototype.toString.call([]);// "[object Array]"Object.prototype.toString.call(null);// "[object Null]"Object.prototype.toString.call(undefined);// "[object Undefined]"4. ⚠️ 常见坑点与面试题
❌ 坑点 1:null和undefined的区别
undefined:表示“缺少值”,即这里应该有一个值,但是还没定义。- 变量声明未赋值。
- 函数参数未传。
- 对象属性不存在。
null:表示“空值”,即这里有一个值,但是是空的。通常用于手动释放对象引用。
leta;console.log(a);// undefinedletb=null;console.log(b);// null❌ 坑点 2:NaN是什么?
NaN(Not a Number) 是 Number 类型的一个特殊值。- 特性:
NaN !== NaN。这是 JS 中唯一一个不等于自身的值。 - 检测:使用
Number.isNaN()或全局isNaN()(后者有类型转换陷阱,推荐前者)。
console.log(NaN===NaN);// falseconsole.log(Number.isNaN(NaN));// trueconsole.log(Number.isNaN("abc"));// false ("abc" 不是 NaN,它是字符串)❌ 坑点 3:包装对象(Wrapper Objects)
基本类型(String, Number, Boolean)在调用方法时,JS 引擎会临时创建一个对应的包装对象,调用完后销毁。
letstr="hello";console.log(str.length);// 5// 内部过程:// 1. 创建 new String("hello")// 2. 获取 length 属性// 3. 销毁临时对象建议:不要手动
new String()、new Number(),这会创建引用类型,导致typeof判断为'object',引发意外 Bug。
5. 💻 实战技巧:类型转换与判断
✅ 显式转换
// 转 NumberNumber("123");// 123parseInt("123px");// 123parseFloat("3.14m");// 3.14// 转 StringString(123);// "123"(123).toString();// "123"// 转 BooleanBoolean("");// falseBoolean(0);// falseBoolean(null);// falseBoolean(undefined);// falseBoolean(NaN);// false// 其余均为 true✅ 封装一个通用的类型判断函数
functiongetType(value){returnObject.prototype.toString.call(value).slice(8,-1).toLowerCase();}console.log(getType([]));// "array"console.log(getType(null));// "null"console.log(getType(newDate()));// "date"console.log(getType(123));// "number"6. 💡 总结
| 类别 | 类型列表 | 存储位置 | 比较方式 | 典型检测 |
|---|---|---|---|---|
| 基本类型 | Number, String, Boolean, Undefined, Null, Symbol, BigInt | 栈 (Stack) | 比值 | typeof |
| 引用类型 | Object (含 Array, Function, Date 等) | 堆 (Heap) | 比地址 | instanceof/toString |
🚀 博主寄语:
数据类型是 JavaScript 的地基。
很多奇怪的 Bug(比如修改了一个数组,另一个数组也变了;或者if (data)判断失效)都源于对类型理解不够深入。记住口诀:
七种基本存栈间,
值拷贝来互不连。
引用对象堆里站,
地址传递牵一线。
Null 本是空对象,
Typeof 检测留遗憾。
精准判断用 toString,
开发避坑保平安。
希望这篇文档能帮你彻底搞懂 JavaScript 的数据类型!如果有疑问,欢迎在评论区留言。👇
喜欢这篇文章吗?记得点赞、收藏、转发哦!❤️