JavaScript 学习笔记(8):面向对象编程与原型机制详解
JavaScript 学习笔记(8):面向对象编程与原型机制详解
woodfish所有的对象里面都有 __proto__
对象原型 指向原型对象
所有的原型对象里面有 constructor, 指向 创造改原型对象的构造函数
一、编程思想:从面向过程到面向对象
(一)面向过程
核心逻辑:聚焦 “步骤”,将问题拆解为一系列连续的操作,用函数实现每个步骤,最终按顺序调用完成任务。
案例
:制作蛋炒饭
- 函数 1:
准备食材(米饭、鸡蛋、葱花)
- 函数 2:
热油(锅、油)
- 函数 3:
炒鸡蛋(鸡蛋、油)
- 函数 4:
混合翻炒(米饭、鸡蛋、盐)
- 执行顺序:
准备食材()
→热油()
→炒鸡蛋()
→混合翻炒()
- 函数 1:
适用场景:简单任务(如计算器、单步骤工具),逻辑直接但扩展性差。
(二)面向对象
核心逻辑:聚焦 “对象”,将问题拆解为具有特定功能的对象,通过对象间的协作完成任务。每个对象包含 “数据”(属性)和 “操作”(方法)。
三大特性
- 封装性:对象内部数据和方法被包裹,仅暴露必要接口(如 “手机” 对象封装了 “芯片”“电池” 等内部组件,只暴露 “打电话”“发消息” 等方法)。
- 继承性:子类可复用父类的属性和方法(如 “智能手机” 继承 “手机” 的 “通话” 功能,新增 “上网” 功能)。
- 多态性:同一方法在不同对象上有不同实现(如 “支付” 方法,支付宝对象实现 “扫码支付”,微信对象实现 “转账支付”)。
案例
制作蛋炒饭
- 食材对象(属性:米饭、鸡蛋、调料;方法:
提供原料()
) - 厨师对象(属性:姓名;方法:
热油()
、翻炒()
、调味()
) - 协作:厨师对象调用食材对象的
提供原料()
,再通过自身翻炒()
等方法完成制作。
- 食材对象(属性:米饭、鸡蛋、调料;方法:
优势:代码复用性高、易维护,适合大型项目(如电商系统、管理平台)。
二、构造函数:面向对象的基础封装方式
核心概念
构造函数是创建对象的 “模板”,通过this
绑定属性和方法,实例化后生成独立的对象,实现数据与行为的封装。
用法示例
1 | // 定义构造函数(首字母大写,区分普通函数) |
问题分析
- 内存浪费:每个实例对象都会复制构造函数内的方法(如
setName
、getName
)。若创建 100 个实例,会存在 100 份相同的方法副本,占用多余内存。 - 解决方案:通过原型对象共享方法,避免重复创建。
三、原型对象(prototype):共享方法的核心
核心概念
- 每个构造函数都有一个
prototype
属性,指向原型对象。 - 原型对象上的方法 / 属性可被所有实例共享,实例化时不会重复创建,节省内存。
- 构造函数、原型对象、实例的关系:
实例.__proto__ === 构造函数.prototype
(实例通过__proto__
关联原型对象)。
用法示例
1. 原型对象挂载共享方法
1 | function Person() { |
2. 方法查找规则(就近原则)
实例访问方法时,优先查找自身,若没有则查找原型对象:
1 | function Person() { |
四、constructor 属性:原型与构造函数的 “身份证”
核心作用
每个原型对象默认有constructor
属性,指向其对应的构造函数,用于标识 “谁创建了这个原型对象”。
常见问题与解决
当用对象字面量重写原型时,会覆盖原有constructor
,需手动修正:
1 | function Person() {} |
五、对象原型(proto):原型链的连接纽带
核心概念
- 每个实例对象都有
__proto__
属性(非标准属性,浏览器实现),指向其构造函数的prototype
原型对象。 - 作用:为对象查找原型属性 / 方法提供 “路径”。
注意事项
__proto__
与[[prototype]]
意义相同([[prototype]]
是 ES 规范中的内部属性,__proto__
是浏览器暴露的访问方式)。__proto__
的constructor
属性指向实例的构造函数(如p.__proto__.constructor === Person
)。
六、原型继承:复用代码的高效方式
核心逻辑
通过将子类的原型设置为父类的实例,使子类继承父类的属性和方法,实现代码复用。
用法示例
1 | // 父类:人(共有的属性和方法) |
七、原型链:属性查找的链式机制
核心概念
- 原型对象本身也是对象,其
__proto__
会指向更高层级的原型对象,形成链式结构(原型链)。 - 终点:所有对象的原型链最终指向
Object.prototype
,而Object.prototype.__proto__
为null
(原型链的尽头)。
属性查找规则
对象访问属性 / 方法时,按以下顺序查找:
自身属性 → 实例.proto(构造函数.prototype) → 原型.proto → … → Object.prototype → null(找不到则返回undefined
)。
示例验证
1 | function Person() { |
instanceof 运算符
检测构造函数的prototype
是否在实例的原型链上(判断对象类型的核心依据):
1 | console.log(p instanceof Person); // true(Person.prototype在p的原型链上) |
总结
- 面向对象编程通过 “对象” 封装数据与行为,依托封装、继承、多态提升代码复用性和可维护性。
- 构造函数是创建对象的模板,但存在方法重复创建的问题,需通过原型对象(
prototype
)共享方法解决。 - 原型链是属性查找的底层机制,通过
__proto__
连接各级原型,最终指向Object.prototype
。 - 原型继承是 JavaScript 实现继承的核心方式,通过修改子类原型为父类实例实现代码复用,同时需修正
constructor
指向。