在 JavaScript 中,原型链(Prototype Chain)是实现对象继承和属性共享的核心机制,理解它是掌握 JS 面向对象特性的关键。
一、什么是原型链?
要理解原型链,首先需要明确两个核心概念:原型(Prototype) 和 原型指向。
- 原型(Prototype) :每个 JavaScript 对象(除
null
外)在创建时都会关联另一个对象,这个 "另一个对象" 就是它的原型。可以理解为:原型是对象的 "模板" ,对象可以访问原型中的属性和方法。 - 原型指向 :对象通过内部属性(通常用
__proto__
表示,标准中推荐用Object.getPrototypeOf()
方法获取)指向它的原型;而函数(特殊的对象)会有一个prototype
属性,指向该函数创建的实例的原型。 - 原型链的形成 :当访问一个对象的属性或方法时,JS 引擎会先在对象自身查找;如果找不到,就会通过
__proto__
去它的原型上查找;如果原型上也没有,就去原型的原型上查找...... 直到找到目标或查到原型链的终点(null
)。这个层层查找的链条,就是原型链。
二、原型链的工作机制
用一个简单的例子说明:
js
// 1. 定义构造函数
function Person(name) {
this.name = name; // 实例自身属性
}
// 2. 在构造函数的原型上定义方法(所有实例共享)
Person.prototype.sayHello = function() {
console.log(`Hello, ${this.name}`);
};
// 3. 创建实例
const person1 = new Person("Alice");
// 4. 访问属性和方法
console.log(person1.name); // "Alice"(自身属性)
person1.sayHello(); // "Hello, Alice"(从原型上找到)
// 5. 原型链结构
console.log(person1.__proto__ === Person.prototype); // true(实例的原型是构造函数的 prototype)
console.log(Person.prototype.__proto__ === Object.prototype); // true(构造函数原型的原型是 Object 的原型)
console.log(Object.prototype.__proto__); // null(原型链的终点)
在这个例子中,person1
的原型链是:person1 → Person.prototype → Object.prototype → null
三、原型链的作用
原型链是 JS 实现继承和代码复用的核心,主要作用体现在以下几个方面:
- 实现继承 :原型链是 JS 中 "继承" 的本质。子对象可以通过原型链访问父对象(原型)的属性和方法,从而实现属性和行为的复用。例如,
Array
的实例能使用push()
、forEach()
等方法,就是因为这些方法定义在Array.prototype
上,而Array.prototype
的原型又指向Object.prototype
,因此数组也能访问toString()
等方法。 - 属性和方法的共享 :定义在原型上的属性和方法,会被所有实例共享,而不是每个实例单独创建一份。这大大节省了内存空间。例如,上述
Person
构造函数的sayHello
方法定义在Person.prototype
上,所有Person
实例都能使用它,而不会为每个实例单独分配内存。 - 实现对象的动态特性:原型链的查找是动态的:如果修改了原型中的属性或方法,所有依赖该原型的实例都会受到影响(即使实例是修改前创建的)。
js
// 给 Person.prototype 新增方法
Person.prototype.sayGoodbye = function() {
console.log(`Goodbye, ${this.name}`);
};
person1.sayGoodbye(); // "Goodbye, Alice"(旧实例也能访问新方法)
- 统一对象的基础行为 所有对象的原型链最终都会指向
Object.prototype
,因此 JS 中所有对象都能共享Object
原型上的基础方法(如toString()
、hasOwnProperty()
等),保证了对象行为的一致性。
四、注意点
- 查找机制的只读性:原型链仅用于 "查找" 属性 / 方法,不能通过实例直接修改原型上的属性(除非显式操作原型对象)。例如,给实例添加与原型同名的属性,只会在实例自身创建该属性,不会覆盖原型上的。
__proto__
与prototype
的区别 :__proto__
是对象的属性(指向原型),prototype
是函数的属性(指向该函数创建的实例的原型)。- 原型链不宜过长:过长的原型链会导致属性查找效率降低,应避免过度嵌套。
总结:原型链是 JavaScript 中对象之间关联的纽带,它通过 "原型指向" 形成层级关系,实现了继承、属性共享和动态特性,是 JS 面向对象编程的基础。