小白也能懂:JavaScript 原型链和隐藏类的奇妙世界
大家好!今天我们来聊聊 JavaScript 里两个听起来高大上但其实很简单的概念:原型链 和隐藏类。别被名字吓到,我会用最生活化的方式解释给你听!
一、原型链:JavaScript 的"家族族谱" 🧬
想象你有一个玩具箱(对象),你想找某个玩具(属性):
javascript
const myToyBox = {
car: "红色小汽车", // 自己的玩具
};
当你直接找 myToyBox.car
,立刻就能找到。但如果想找一个不存在的玩具呢?
javascript
console.log(myToyBox.robot); // 自己箱子里没有!
这时 JavaScript 会去"爸爸的玩具箱"里找 → 这就是原型链!
javascript
// 爸爸的玩具箱
const dadsToyBox = {
robot: "变形金刚"
};
// 设置爸爸的箱子为你的原型
Object.setPrototypeOf(myToyBox, dadsToyBox);
console.log(myToyBox.robot); // ✅ 找到了变形金刚!
查找过程就像寻宝游戏:
- 先翻自己的箱子(对象自身)
- 找不到就去爸爸的箱子(原型对象)
- 还找不到就去爷爷的箱子(原型的原型)
- 直到找到或家族尽头(null)
(示意图:对象 → 原型 → 原型的原型 → null)

🔑 关键点 :当你用
对象.属性
时,JavaScript 会沿着这条"家族链"层层查找!
二、原型链是链表吗?底层揭秘 🔍
很多教程说原型链像"链表",对也不对:
- ✅ 行为像链表:通过指针连接,顺序查找
- ❌ 实现非链表:引擎用更高级方式优化
看个底层伪代码(V8引擎简化版):
cpp
// 当访问 obj.property 时
Object* current = obj;
while (current != null) {
if (current->HasProperty("property")) {
return value; // 找到就返回
}
current = current->prototype; // 跳转到下一个原型
}
return undefined; // 找不到
就像你按地址串门找人:
javascript
你家(对象)→ 爸爸家(原型)→ 爷爷家(Object.prototype)→ 终点(null)
三、隐藏类:引擎的"超强记忆术" 🧠
如果每次查属性都要遍历整条链,岂不慢死?别怕!JavaScript 引擎有个秘密武器------隐藏类。
什么是隐藏类?
想象你去学校图书馆:
- ❌ 无隐藏类:每次借书都从头找书名(超慢!)
- ✅ 有隐藏类:管理员记住"科幻区第3书架"(直接拿书)
代码示例:
javascript
// 创建两个相同结构的对象
const obj1 = {};
obj1.name = "小明"; // 触发隐藏类 C1
obj1.age = 12; // 转换到隐藏类 C2
const obj2 = {};
obj2.name = "小红"; // 同样触发 C1 → C2 转换
这时引擎会:
- 为
{name, age}
结构创建共享的隐藏类 - 记录
name
和age
在内存中的固定位置 - 后续访问时直接跳转地址(比查字典快10倍!)
什么时候会"失忆"?
javascript
// ❌ 错误示范:打乱属性顺序
const obj3 = {};
obj3.age = 12; // 创建新隐藏类 C3
obj3.name = "小刚"; // 转换到 C4(与 obj1/obj2 不同!)
📝 最佳实践 :
✅ 按固定顺序初始化属性
✅ 尽量在构造函数中赋值
❌ 避免动态增删属性
总结:三句话掌握精髓 💡
- 原型链是 JS 的属性查找机制------像家族寻亲,层层向上找
- 点操作符(.) 触发原型链遍历------从自己到原型链尽头
- 隐藏类是引擎的优化术------用固定内存布局加速访问
下次看到 obj.property
,你就知道背后有一段精彩的"寻亲之旅"啦!建议写个简单例子体验一下,代码是最好的老师哦~
javascript
// 动手实验!
const grandpa = { hobby: "钓鱼" };
const father = { job: "工程师" };
Object.setPrototypeOf(father, grandpa);
const me = {};
Object.setPrototypeOf(me, father);
console.log(me.hobby); // 试试输出什么?