深入理解 JavaScript 原型与原型链
一、原型(Prototype):一切皆对象的起点
在 JavaScript 中,每个对象都有一个隐藏的 [[Prototype]] 属性(现代浏览器可通过 __proto__ 访问),这是 JS 实现继承的基石。当你创建一个新对象时,它会自动关联一个原型对象,形成继承关系链。
代码示例:
// 构造函数
function Person(name) {
this.name = name;
}
// 给原型添加方法
Person.prototype.greet = function() {
console.log(`Hello, I'm ${this.name}`);
}
const alice = new Person("Alice");
alice.greet(); // 调用原型方法
原型示意图:
二、原型链:层层递进的继承网络
当访问对象属性时,JS 引擎会执行以下搜索:
- 检查对象自身属性
- 沿
__proto__向上查找原型对象 - 直到 Object.prototype 停止(其
__proto__为 null)
原型链验证:
console.log(alice.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
原型链示意图:
三、核心概念对比
| 特性 | __proto__ | prototype |
|---|---|---|
| 归属对象 | 所有对象 | 仅函数对象 |
| 标准访问方式 | Object.getPrototypeOf(obj) | 函数默认属性 |
| 作用 | 实现原型继承 | 作为构造函数创建实例的原型 |
四、实现继承的演进之路
1. 组合继承(经典模式)
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(`${this.name} is eating`);
}
function Dog(name, breed) {
Animal.call(this, name); // 继承属性
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log("Woof!");
}
2. 现代 class 语法(ES6+)
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} is eating`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log("Woof!");
}
}
五、关键注意事项
- 原型修改时机:在创建实例后修改原型会影响所有实例
- 性能优化:过长的原型链会影响查找效率
- 属性屏蔽:实例属性会覆盖原型同名属性
- 现代实践:推荐使用
Object.create()代替直接修改__proto__
六、调试技巧
// 检查原型链
console.log(alice instanceof Person); // true
// 查看对象自身属性
console.log(Object.keys(alice)); // ["name"]
// 检测属性来源
console.log(alice.hasOwnProperty('greet')); // false
console.log('greet' in alice); // true
七、总结与展望
理解原型链机制是掌握 JavaScript 面向对象编程的关键。虽然现代 ES6 class 语法让继承更直观,但其底层仍然是基于原型链实现。