JS 中面向对象的编程——原型对象和方法

三种不同的方法
这个问题非常核心,彻底搞懂它,对于理解 JS 的面向对象编程、性能优化和代码组织至关重要。
先来看我写的这个例子,如果能看懂,本章可以直接过了。
1 | // ================ 定义部分 |
下面就假设我们要创建一个“小狗”的“类”,来演示三种方法。
1. 实例方法 (挂在 prototype
上) —— 共享的“种族天赋” 🐕🦺
代码示例
ES6 class 写法
1 | class Dog { |
等价的构造函数语法
1 | function Dog(name) { |
这是最常用、最高效的方式。你可以把它想象成所有小狗都与生俱来的、写在基因里的通用技能,比如“吠叫”、“奔跑”。我们不需要为每一只新出生的小狗都单独教一遍,它们天生就会。
-
工作原理:这个方法只在内存中存在一份,位于
Dog.prototype
这个“技能原型”对象上。当你创建一个新的小狗实例(如d1
)时,d1
内部有一个特殊的[[Prototype]]
链接指向Dog.prototype
。当你调用d1.bark()
时,JS 引擎在d1
自身上找不到bark
方法,就会顺着链接去Dog.prototype
上找,并执行它。 -
this
指向:this
永远指向调用该方法的实例(谁调用,this
就是谁)。比如d1.bark()
里的this
就是d1
。
✅ 总结
- 内存占用:极低,所有实例共享一个方法。
- 适用场景:95% 的情况都应该用它。所有与实例状态(如
this.name
)相关、且所有实例都通用的行为,都应该定义为实例方法。
2. 对象自带方法 (写在 constructor
里) —— “专属定制技能” 🎓
代码示例
ES6 class 写法
1 | class Dog { |
等价的构造函数语法
1 | function Dog(name) { |
这种方法是为每一只小狗单独定制的技能。比如,我们给一只小狗请了个一对一的私教,教了它一个只有它自己会、而且和它“签约”时(new
的时候)的某些特定信息相关的特殊技能。
-
工作原理:每执行一次
new Dog(...)
,构造函数内部的代码就会运行一次。这意味着每次都会创建一个新的函数,并把它作为属性直接挂载到新生成的实例上。 -
this
指向:this
同样指向调用该方法的实例。
代码示例
1 | class Dog { |
✅ 总结
-
内存占用:高,每个实例都有一份方法的副本。
-
适用场景:
- 当方法需要访问构造函数作用域中的私有变量(形成闭包)时。这是它最主要的用途。
- 当你想为不同实例提供不同版本的方法实现时(虽然通常有更好的设计模式)。
- 在现代开发中,除非有明确的闭包需求,否则应避免使用这种方式,以优化性能。
3. 静态方法 (挂在构造函数上) —— “犬类研究中心”的工具 🔬
ES6 class 写法
1 | class Dog { |
等价的构造函数语法
1 | function Dog() { |
静态方法不属于任何一只具体的小狗,而是属于 Dog
这个“物种”或“犬类研究中心”本身。它通常是一些辅助函数或工厂函数,与单个小狗的状态无关。比如,“创建一个随机名字的小狗”或者“比较两只狗的年龄”,这些操作不需要一只已经存在的小狗来发起。
-
工作原理:方法直接附加在
Dog
构造函数这个对象上,而不是在它的prototype
上。因此,实例无法访问到它。 -
this
指向:在静态方法内部,this
指向构造函数本身(即Dog
),而不是任何实例。
代码示例 (现代 ES6 Class 语法 - 推荐)
1 | class Dog { |
✅ 总结
- 内存占用:极低,和类本身绑定在一起,只有一份。
- 适用场景:当你需要一个不依赖于实例状态的工具函数时。比如:
- 工厂方法(如
Dog.create...
) - 配置(如
Dog.config = {...}
) - 纯工具函数(如
Math.max()
,Array.from()
都是典型的静态方法)
- 工厂方法(如
终极对比表格
特性 | 实例方法 (prototype) | 对象自带方法 (constructor) | 静态方法 (static) |
---|---|---|---|
定义位置 | class 的顶级作用域内 / Constructor.prototype |
constructor 内部 |
class 内用 static / Constructor 上 |
调用方式 | 实例.方法() |
实例.方法() |
类.方法() |
this 指向 |
调用它的实例 | 调用它的实例 | 类(构造函数)本身 |
内存占用 | 极低 (所有实例共享) | 高 (每个实例一份拷贝) | 极低 (类本身持有一份) |
核心用途 | 实例的核心、通用行为 (主要使用方式) | 需要访问构造函数闭包变量的特殊方法 | 工具函数、工厂函数,与实例状态无关 |
比喻 | 种族天赋 (Shared) | 私教定制技能 (Per-Instance) | 犬类研究中心的工具 (Utility) |
现代前端开发实践建议
- 首选实例方法 (prototype):这是定义对象行为的默认和最佳方式。它性能好,符合面向对象的直觉。
- 慎用构造函数内方法:只在你确定需要利用闭包来封装私有状态时才使用。否则,它会造成不必要的内存浪费。
- 善用静态方法:将所有与类相关但与具体实例无关的功能(如创建、转换、通用计算)组织为静态方法,这会让你的代码结构更清晰。
- 标题: JS 中面向对象的编程——原型对象和方法
- 作者: 三葉Leaves
- 创建于 : 2025-06-06 00:00:00
- 更新于 : 2025-06-07 19:46:13
- 链接: https://blog.oksanye.com/8826998fb3d7/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。