原型(Prototype)是计算机科学中一个重要的概念,尤其在 JavaScript 和 面向对象编程(OOP) 中具有核心地位。以下是关于原型的详细介绍:
1. 什么是原型?
- 定义:原型(Prototype)是一个对象,它作为其他对象的模板,提供共享的属性和方法。新对象可以通过继承原型来复用这些属性和方法。
- 核心思想:基于原型的继承(Prototype-based Inheritance),与基于类的继承(Class-based Inheritance)不同,允许对象直接继承其他对象。
2. JavaScript 中的原型
在 JavaScript 中,每个对象都有一个隐藏的 [[Prototype]] 属性(可通过 __proto__ 访问),指向它的原型对象。当访问对象的属性或方法时,若对象自身不存在该属性,则会沿着原型链(Prototype Chain)向上查找,直到找到或到达原型链的末端(null)。
关键概念:
- 构造函数(Constructor):通过
new关键字创建对象的函数。构造函数有一个prototype属性,指向其原型对象。 - 原型对象(Prototype Object):包含共享属性和方法的对象,由构造函数创建的所有实例共同继承。
- 原型链(Prototype Chain):对象通过
[[Prototype]]形成的链式结构,用于实现继承。
示例代码:
// 构造函数
function Person(name) {
this.name = name;
}
// 在原型上添加方法(共享)
Person.prototype.sayHello = function() {
console.log(`Hello, I'm ${this.name}`);
};
// 创建实例
const alice = new Person("Alice");
alice.sayHello(); // "Hello, I'm Alice"
// 原型链:alice -> Person.prototype -> Object.prototype -> null
3. 原型继承的机制
-
构造函数与原型的关系:
- 构造函数的
prototype属性指向原型对象。 - 原型对象的
constructor属性指回构造函数。 - 实例的
__proto__指向构造函数的prototype。
Person.prototype.constructor === Person; // true alice.__proto__ === Person.prototype; // true - 构造函数的
-
属性查找规则:
- 当访问
alice.sayHello()时,先在实例自身查找。 - 若未找到,则通过
alice.__proto__查找Person.prototype。 - 若仍未找到,继续沿着原型链向上查找,直到
Object.prototype或null。
- 当访问
4. 原型链的终点
- 所有对象的原型链最终指向
Object.prototype,而Object.prototype.__proto__为null。 - 例如:
alice.__proto__.__proto__ === Object.prototype(true)。
5. 修改原型
- 动态性:JavaScript 的原型是动态的,修改原型对象会立即影响所有实例。
Person.prototype.sayBye = function() { console.log("Bye!") }; alice.sayBye(); // 新增方法对所有实例生效 - 覆盖原型:直接替换
prototype会断开已有实例与原型的联系。Person.prototype = { newMethod() {} }; const bob = new Person("Bob"); bob.sayHello(); // 报错,旧方法已丢失
6. 原型继承的优缺点
优点:
- 内存高效:共享方法只需定义一次,所有实例复用。
- 灵活性:动态修改原型,扩展功能方便。
缺点:
- 共享引用类型属性:若原型包含引用类型(如数组),所有实例会共享同一份数据。
- 性能问题:过长的原型链可能影响查找速度。
7. ES6 中的 class 语法
ES6 引入了 class 关键字,但其本质仍是基于原型的语法糖:
class Person {
constructor(name) { this.name = name; }
sayHello() { console.log(`Hello, I'm ${this.name}`); }
}
typeof Person; // "function"(类本质是函数)
8. 其他应用场景
- 原型模式:设计模式中,通过克隆原型对象创建新对象,避免重复初始化。
- 原型工具方法:如
Object.create()直接基于原型创建对象:const animal = { eats: true }; const rabbit = Object.create(animal); console.log(rabbit.eats); // true
总结
原型是 JavaScript 实现继承和共享行为的核心机制。理解原型链、构造函数与原型对象的关系,是掌握 JavaScript 面向对象编程的关键。通过合理使用原型,可以写出高效、灵活的代码,同时避免共享数据导致的意外问题。