深入理解 JavaScript 原型机制:从“如何拿到小米 SU7”说起

"孔子是韩国人?"------JS 的原型链不是血缘,而是委托。

在前端开发中,JavaScript 的原型(prototype)机制常常让人困惑又着迷。它不像 Java、C++ 那样基于"类"的继承,而是一种基于原型的委托式面向对象模型。今天,我们就用一个轻松的例子------"如何拿到一辆小米 SU7"------来揭开原型机制的神秘面纱。


一、构造函数:造车的第一步

假设你想拥有一辆小米 SU7,首先得有个"造车蓝图"。在 JS 中,这个蓝图就是构造函数

ini 复制代码
Javascript
编辑
1function Car(color) {
2    this.color = color;
3}

当你执行 new Car('霞光紫') 时,JS 引擎会:

  1. 创建一个新对象;
  2. this 指向这个新对象;
  3. 执行构造函数中的代码(如设置 color);
  4. 返回这个新对象。

此时,你得到了一辆"独属于你"的 SU7,颜色是霞光紫。

但问题来了:每辆车都要有 drive 方法、长宽高参数吗? 如果每个实例都存一份,岂不浪费内存?


二、prototype:共享的"公共配置"

于是 JS 引入了 prototype(原型) ------所有实例共享的方法和属性存放地。

javascript 复制代码
Javascript
编辑
1Car.prototype = {
2    name: 'su7',
3    height: 1.4,
4    weight: 1.5,
5    long: 4800,
6    drive() {
7        console.log('drive, 下赛道');
8    }
9};

现在,无论你创建多少辆 SU7,它们都共享同一份原型对象 。调用 car1.drive() 时,JS 会在 car1 自身找不到 drive,就沿着 __proto__ 链向上查找,最终在 Car.prototype 上找到。

关键点

  • 实例属性(如 color)存在实例自身;
  • 共享方法/属性(如 drive, name)存在原型上;
  • 查找顺序:实例 → 原型 → 原型的原型 → ... → Object.prototype → null

三、原型链的本质:委托,而非继承

很多人误以为 JS 是"类继承",其实它是对象委托

  • 传统 OOP(如 Java):子类"继承"父类,形成血缘关系。
  • JS 原型式 OOP:对象"委托"给另一个对象,说:"你有这方法吗?借我用用。"

比如:

ini 复制代码
Javascript
编辑
1var obj = {};
2console.log(obj.toString()); // 能调用!

obj 自己没有 toString,但它通过 __proto__ 委托给了 Object.prototype,于是成功调用。

这种设计更灵活:你可以随时修改原型,所有实例立即"感知"到变化(除非实例自己覆盖了该属性)。


四、constructor 与原型的"双向绑定"

每个函数都有 prototype 属性,而 prototype 对象默认有一个 constructor 属性,指回构造函数:

ini 复制代码
Javascript
编辑
1Car.prototype.constructor === Car; // true

但注意!如果你直接重写整个 prototype (如 Car.prototype = { ... }),这个链接会被切断:

ini 复制代码
Javascript
编辑
1Car.prototype = { drive() {} };
2console.log(Car.prototype.constructor === Car); // false! 现在是 Object

修复方式:

javascript 复制代码
Javascript
编辑
1Car.prototype = {
2    constructor: Car, // 手动修复
3    drive() { /*...*/ }
4};

或者使用 Object.defineProperty 设置不可枚举的 constructor


五、多层原型链:Animal → Person → su

JS 支持原型链的嵌套,模拟"多级继承":

javascript 复制代码
Javascript
编辑
1function Animal() {}
2Animal.prototype.species = '动物';
3
4function Person() {}
5Person.prototype = new Animal(); // Person 委托给 Animal 实例
6
7var su = new Person();
8console.log(su.species); // '动物'

这里 su.__proto__Person.prototype(即一个 Animal 实例),而 Animal 实例的 __proto__ 又指向 Animal.prototype,最终通向 Object.prototype

🌟 这就是为什么 su.toString() 依然有效------原型链一路向上,直到 Object.prototype


六、思考:为什么 JS 选择原型?

  • 动态性:运行时可修改原型,行为实时生效;
  • 轻量:无需预定义"类",对象可自由扩展;
  • 哲学差异:JS 认为"对象之间可以互相学习",而非"必须出自某个模板"。

正如道家思想:"上善若水,水善利万物而不争。"

JS 的原型链,也是一种"无为而治"的委托之道。


结语

下次当你写下 new Car() 时,不妨想想:

你不仅创建了一个对象,还开启了一段沿着原型链向上委托的旅程

而那辆小米 SU7,或许不在展厅,而在 Car.prototype 的深处,静静等待被"驱动"。

相关推荐
Hilaku33 分钟前
我用 Gemini 3 Pro 手搓了一个并发邮件群发神器(附源码)
前端·javascript·github
IT_陈寒34 分钟前
Java性能调优实战:5个被低估却提升30%效率的JVM参数
前端·人工智能·后端
快手技术35 分钟前
AAAI 2026|全面发力!快手斩获 3 篇 Oral,12 篇论文入选!
前端·后端·算法
颜酱36 分钟前
前端算法必备:滑动窗口从入门到很熟练(最长/最短/计数三大类型)
前端·后端·算法
全栈前端老曹1 小时前
【包管理】npm init 项目名后底层发生了什么的完整逻辑
前端·javascript·npm·node.js·json·包管理·底层原理
HHHHHY1 小时前
mathjs简单实现一个数学计算公式及校验组件
前端·javascript·vue.js
boooooooom1 小时前
Vue3 provide/inject 跨层级通信:最佳实践与避坑指南
前端·vue.js
一颗烂土豆1 小时前
Vue 3 + Three.js 打造轻量级 3D 图表库 —— chart3
前端·vue.js·数据可视化
青莲8431 小时前
Android 动画机制完整详解
android·前端·面试
iReachers1 小时前
HTML打包APK(安卓APP)中下载功能常见问题和详细介绍
前端·javascript·html·html打包apk·网页打包app·下载功能