JavaScript原型链详解
约 1529 字大约 5 分钟
javascriptprototype
2025-07-22
概述
原型链是 JavaScript 对象继承的核心机制。每个对象都有一个内部链接指向另一个对象——它的"原型",这种链式结构一直延伸到 null 为止。理解原型链是掌握 JavaScript 面向对象编程的基础。
核心概念关系
1. prototype、__proto__ 与 constructor
这三者的关系是理解原型链的基石。
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
return `Hello, I'm ${this.name}`;
};
const alice = new Person('Alice');
// 三者关系
console.log(alice.__proto__ === Person.prototype); // true
console.log(Person.prototype.constructor === Person); // true
console.log(alice.constructor === Person); // true (通过原型链查找)
// __proto__ 是对象实例的属性,指向构造函数的 prototype
// prototype 是函数的属性,是实例的原型对象
// constructor 是 prototype 上的属性,指回构造函数关系总结
2. 原型链查找机制
当访问对象属性时,JavaScript 引擎沿原型链逐级查找:
function Animal(type) {
this.type = type;
}
Animal.prototype.breathe = function() { return 'breathing'; };
function Dog(name) {
Animal.call(this, 'dog');
this.name = name;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() { return 'Woof!'; };
const buddy = new Dog('Buddy');
// 属性查找路径
console.log(buddy.name); // 'Buddy' → 实例自身属性
console.log(buddy.bark()); // 'Woof!' → Dog.prototype
console.log(buddy.breathe());// 'breathing' → Animal.prototype
console.log(buddy.toString());// '[object Object]' → Object.prototype
// 查找链:buddy → Dog.prototype → Animal.prototype → Object.prototype → null3. Object.create
Object.create() 创建一个新对象,使用提供的对象作为新对象的 __proto__。
const baseConfig = {
debug: false,
version: '1.0',
getInfo() {
return `v${this.version} (debug: ${this.debug})`;
}
};
// 创建以 baseConfig 为原型的新对象
const devConfig = Object.create(baseConfig);
devConfig.debug = true;
devConfig.version = '1.1-dev';
console.log(devConfig.getInfo()); // "v1.1-dev (debug: true)"
console.log(devConfig.hasOwnProperty('debug')); // true
console.log(devConfig.hasOwnProperty('getInfo')); // false(在原型上)
// Object.create(null) 创建无原型对象(纯净字典)
const dict = Object.create(null);
dict.key = 'value';
console.log(dict.toString); // undefined(没有原型链)4. class 语法糖
ES6 的 class 是基于原型链的语法糖,本质不变。
class Vehicle {
constructor(brand) {
this.brand = brand;
}
start() {
return `${this.brand} engine started`;
}
static compare(v1, v2) {
return v1.brand === v2.brand;
}
}
class Car extends Vehicle {
constructor(brand, model) {
super(brand); // 调用父类构造函数
this.model = model;
}
describe() {
return `${this.brand} ${this.model}`;
}
}
const car = new Car('Toyota', 'Camry');
// 验证原型链关系
console.log(car instanceof Car); // true
console.log(car instanceof Vehicle); // true
console.log(Car.prototype.__proto__ === Vehicle.prototype); // true
// class 的本质
console.log(typeof Vehicle); // 'function'
console.log(Vehicle.prototype.constructor === Vehicle); // trueclass 与构造函数的等价关系
5. 继承模式
原型链继承
function Parent() {
this.colors = ['red', 'blue'];
}
Parent.prototype.getColors = function() { return this.colors; };
function Child() {}
Child.prototype = new Parent(); // 原型链继承
const c1 = new Child();
const c2 = new Child();
c1.colors.push('green');
console.log(c2.colors); // ['red', 'blue', 'green'] — 引用类型共享问题!组合继承(最常用的经典模式)
function Parent(name) {
this.name = name;
this.skills = [];
}
Parent.prototype.addSkill = function(skill) {
this.skills.push(skill);
};
function Child(name, age) {
Parent.call(this, name); // 借用构造函数(继承实例属性)
this.age = age;
}
Child.prototype = Object.create(Parent.prototype); // 原型链继承(继承方法)
Child.prototype.constructor = Child;
const c1 = new Child('Alice', 10);
const c2 = new Child('Bob', 12);
c1.addSkill('JS');
console.log(c2.skills); // [] — 各自独立寄生组合继承
function inheritPrototype(SubType, SuperType) {
const prototype = Object.create(SuperType.prototype);
prototype.constructor = SubType;
SubType.prototype = prototype;
}
function SuperType(name) {
this.name = name;
}
SuperType.prototype.sayName = function() { return this.name; };
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function() { return this.age; };6. instanceof 原理
instanceof 检查构造函数的 prototype 是否出现在对象的原型链上。
// instanceof 的简化实现
function myInstanceOf(obj, Constructor) {
let proto = Object.getPrototypeOf(obj);
const target = Constructor.prototype;
while (proto !== null) {
if (proto === target) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}
class A {}
class B extends A {}
class C extends B {}
const c = new C();
console.log(c instanceof C); // true
console.log(c instanceof B); // true
console.log(c instanceof A); // true
console.log(c instanceof Object); // true7. 属性遮蔽(Property Shadowing)
当对象自身定义了与原型链上同名的属性时,会遮蔽原型上的属性。
function Base() {}
Base.prototype.value = 42;
Base.prototype.data = [1, 2, 3];
const obj = new Base();
// 读取 — 沿原型链查找
console.log(obj.value); // 42(来自原型)
// 赋值 — 在实例自身创建新属性,遮蔽原型
obj.value = 100;
console.log(obj.value); // 100(实例自身)
console.log(obj.hasOwnProperty('value')); // true
console.log(Base.prototype.value); // 42(原型未改变)
// 删除实例属性后恢复原型访问
delete obj.value;
console.log(obj.value); // 42(再次从原型读取)
// 注意:引用类型的修改会影响原型
obj.data.push(4); // 没有遮蔽!直接修改了原型上的数组
console.log(Base.prototype.data); // [1, 2, 3, 4]8. 内置对象的原型链
// 所有内置类型最终都指向 Object.prototype
console.log([].__proto__ === Array.prototype); // true
console.log([].__proto__.__proto__ === Object.prototype); // true
// Function 与 Object 的循环关系
console.log(Function.__proto__ === Function.prototype); // true
console.log(Object.__proto__ === Function.prototype); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true9. 现代 API 替代
// 推荐使用 Object.getPrototypeOf 替代 __proto__
const proto = Object.getPrototypeOf(obj);
// 使用 Object.setPrototypeOf 设置原型(性能较差,慎用)
Object.setPrototypeOf(child, parent);
// 检查自有属性
Object.hasOwn(obj, 'prop'); // ES2022,替代 obj.hasOwnProperty('prop')
// 获取所有自有属性名(包括不可枚举)
Object.getOwnPropertyNames(obj);
// 获取原型链上所有可枚举属性
for (const key in obj) {
console.log(key); // 包含原型链上的可枚举属性
}总结
JavaScript 原型链是对象属性查找和继承的底层机制。prototype 是函数的属性,__proto__ 是实例的内部链接,constructor 连接原型与构造函数。ES6 class 是语法糖,底层仍然是原型链。理解属性遮蔽、instanceof 判定和原型链查找路径,对于调试对象行为和设计继承体系至关重要。
贡献者
更新日志
2026/3/14 13:09
查看所有更新日志
9f6c2-feat: organize wiki content and refresh site setup于