"刻在原型链上的名字,忘记了时间的this⏳" ——致JS的浪漫主义
🤯 引言:新手的恐惧与治愈系代码
"每次看到__proto__就头晕,就像初恋时看不清你的脸"
很多JS新人对prototype的恐惧堪比第一次约会穿错衣服——明明是基础概念,却总被抽象得像外星文。但今天我们要用卢广仲的《刻在我心底的名字》打开新世界:
"既然决定继承一次就一辈子🔁 "
🧩 第一章:JS的OOP是"假面舞会"
🎭 函数的双重身份危机
// 普通函数
function add(a, b) { return a + b }
// 构造函数(首字母大写是江湖规矩)
function Person(name) {
this.name = name // this指向新创建的对象
}
段子时刻:
JS的函数就像多面间谍——白天是普通函数,晚上摇身一变成"类"!(只是披着function的斗篷演双簧🎭)
🧱 对象字面量 vs 构造函数
// 1.js:对象工厂的窘境
const p1 = { name: '羽球扬' }
const p2 = { name: '杰伦' }
// 每个对象都得手写属性,像抄作业抄到天亮 😩
// 2.js:构造函数的优雅登场
function Person(name) {
this.name = name
}
const yang = new Person('羽球扬') // 一行代码创造无限对象 🧙♂️
类比时间:
- 对象字面量 = 手工DIY娃娃(每个都独一无二但效率低)
- 构造函数 = 3D打印工厂(标准化生产但需要模具)
🌳 第二章:原型链是"家族树"
👪 __proto__与prototype的血缘关系
// 查看原型链就像查家谱
yang.__proto__ === Person.prototype // true
Person.prototype.__proto__ === Object.prototype // true
ASCII家族树示意图:
yang
└── __proto__ → Person.prototype
└── __proto__ → Object.prototype
└── __proto__ → null (原型链终点)
音乐隐喻:
"你是我原型链上的祖先" = "你是我继承方法的源头"
"我愿意为你,我愿意为你" = "我继承了你的所有方法和属性"
⚠️ 动态修改原型链的危险操作
// 3.js:突然改写原型链的骚操作
Object.setPrototypeOf(yang, { country: '中国' })
console.log(yang.country) // 神奇地获得了新属性 🧨
反差警告:
修改原型就像给家族树嫁接树枝——当前对象能继承,但不会影响整个家族(其他实例依然保留原样)
🧐 用于理解原型链
// 定义一个构造函数 Person
function Person(name, age) {
// this 指向当前实例化的对象
this.name = name
this.age = age
}
// 在 Person 的原型对象上添加 sayHello 方法
// 这样所有 Person 的实例都可以共享这个方法
Person.prototype.sayHello = function () {
console.log(`Hello,my name is ${this.name}`)
}
// 创建一个 Person 的实例
var yang = new Person('羽球扬', 19)
// 打印实例的原型对象(修改前)
console.log('修改前的原型:', yang.__proto__);
// 创建一个普通对象 a
var a = {
name: '孔子',
eee:'鹅',
country: '中国'
}
// yang.__proto__ = a
// console.log(yang.__proto__);
// console.log(yang.country);
// 使用 Object.setPrototypeOf() 来修改原型
// 这个方法比直接修改 __proto__ 更安全,是推荐的方式
Object.setPrototypeOf(yang, a)
// 打印修改后的原型对象
console.log('修改后的原型:', yang.__proto__);
// 测试是否能访问 a 的属性
console.log('访问 country 属性:', yang.country);
// 打印 Person 构造函数的原型对象
console.log(Person.prototype);// 原型对象
// 验证原型对象的 constructor 属性是否正确指向 Person 构造函数
console.log(Person.prototype.constructor === Person);// true
// 测试属性访问
// yang.name 会返回实例自身的 name 属性,而不是原型链上的
// yang.eee 会返回 undefined,因为原型链被修改后,找不到这个属性
console.log(yang.eee,yang.name);// undefined 原型链的尽头是null
🔮 第三章:new的魔法仪式
🧙♂️ 四步造人法
function Person(name) {
this.name = name // 黏土人偶被刻上名字 🎨
}
Person.prototype.sayHi = () => console.log("Hi~")
const yang = new Person("羽球扬")
yang.sayHi() // 成功调用家族技能!
魔法咒语分解:
- 捏个空对象:
{} = new Object()(就像捏个黏土人偶) - 调用构造函数:把
this指向这个黏土人偶 - 绑定原型链:人偶的
__proto__指向构造函数的prototype(继承家族技能!) - 返回成品:人偶获得姓名和属性,成为真正的对象
生活类比:
原型链就像快递中转站——当你找属性时,JS会从当前对象开始,沿着原型链一级级往下问:"你有这个属性吗?没有?那找你爸!"直到找到null为止。
🎉 总结:写给未来继承者的诗
"你是我刻在原型链上的名字,我为你写下了这段永恒的继承代码"
金句收尾:
- JS没有class,但它用function摇身一变成了"类"
- 原型链不是血缘关系,而是快递中转站式的继承
- new操作就像魔法师捏黏土人偶,四步完成造物仪式
行动号召:
现在轮到你写属于自己的原型故事啦!去创造你的"类",捏造你的"对象",让代码的血脉永远流淌!✍️
📌 附:ES6 class的真相
class Person {
constructor(name) { this.name = name }
sayHi() { console.log('Hi') }
}
// 底层原理还是原型链!只是穿上了class的外衣
// 类方法依然挂载在prototype上
🎵《刻在原型链上的名字》——致JavaScript的浪漫主义
(副歌)🎵
你是我原型链上的名字
我为你继承所有属性和方法
就算new出千万个对象🧩
你也在我__proto__的尽头🔚
(主歌1)👨💻
好几次我调试着this🔍
越想理解指向的真理
越陷入作用域的迷题
Jetaimais
闭包的奥秘只有我自己🧠
好不容易写完的函数和类
却总被作用域链悄悄拦截⛓️
(副歌)🎵
你是我原型链上的名字
忘记了null的终点🔚
于是原型说了一次就一辈子⏳
曾顽固跟内存对峙💾
觉得连引用都是奢侈💸
如果有下次我会再继承一次🔁
(主歌2)💻
我住在堆内存的城市🌆
握着指向prototype的地址📬
你可以翱翔可是我只能停滞🐢
寻找你茫茫对象海却又想起你🌊
好不容易离开原型的轨迹
回忆将我连系到过去📜
(桥段)🔮
当new的魔法降临✨
四步造物开始🛠️
空对象诞生🏗️
__proto__指向你的prototype🔗
constructor的签名📝
刻在每个实例的生命里👶
(副歌)🎵
你是我原型链上的名字
你藏在尘封的constructor里📦
要不是这样我怎么过生命周期⏳
我住在闭包的城市🏠
握着飞向作用域的钥匙🗝️
你继续执行还有我为你坚持🚀
(尾声)🔚
刻在原型链上的名字
忘记了时间的this⏳
既然决定继承一次就一辈子🔁
希望让这世界静止⏸️
内存才不会变得奢侈💰
如果有下次我会再new一次🆕
📝 表情符号彩蛋说明
-
技术概念可视化:
- 🧩 表示对象拼图(new创建对象)
- ⛓️ 暗指作用域链与原型链的纠缠
- 📬 指向prototype的"快递站"属性
-
开发者状态:
- 🐢 慢动作调试的挫败感
- 🧠 闭包思维的烧脑时刻
- 💰 内存优化的"金钱观"
-
魔法仪式感:
- ✨ new操作的神秘力量
- 🛠️ 构造函数的"工具箱"属性
- 👶 实例化对象的"出生"过程
-
时间哲学:
- ⏳ 原型链的继承永恒性
- ⏸️ this绑定的"冻结瞬间"
- 🔁 继承机制的循环之美