JavaScript 原型链基础
原型链是 JavaScript 实现继承的核心机制,每个对象都有一个内部链接指向另一个对象(原型),形成属性查找链。
核心概念
JavaScript
// 每个对象都有 __proto__ 属性(浏览器暴露)
const obj = {};
console.log(obj.__proto__); // Object.prototype
// 函数有 prototype 属性(构造函数专用)
function Foo() {}
console.log(Foo.prototype); // Foo 的原型对象
// 实例的 __proto__ 指向构造函数的 prototype
const instance = new Foo();
console.log(instance.__proto__ === Foo.prototype); // true
原型链结构
JavaScript
// 原型链层级关系
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log('Hello, ' + this.name);
};
const person = new Person('Tom');
// 原型链:
// person.__proto__ → Person.prototype
// Person.prototype.__proto__ → Object.prototype
// Object.prototype.__proto__ → null
console.log(person.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
属性查找机制
JavaScript
// 查找顺序:自身 → 原型链
person.name; // 'Tom'(自身属性)
person.sayHello(); // Person.prototype(原型属性)
person.toString(); // Object.prototype(原型链末端)
// 自身属性 vs 原型属性
console.log(person.hasOwnProperty('name')); // true
console.log(person.hasOwnProperty('sayHello')); // false
console.log(person.hasOwnProperty('toString')); // false
// 属性覆盖(遮蔽)
person.sayHello = function() {
console.log('Override');
};
person.sayHello(); // 'Override'(自身属性优先)
delete person.sayHello;
person.sayHello(); // 'Hello, Tom'(恢复原型属性)
原型链图示
JavaScript
┌─────────────────┐
│ person │
│ name: 'Tom' │
└────────┬────────┘
│ __proto__
↓
┌─────────────────────┐
│ Person.prototype │
│ sayHello: function │
│ constructor: Person│
└────────┬────────────┘
│ __proto__
↓
┌─────────────────────┐
│ Object.prototype │
│ toString, valueOf │
│ hasOwnProperty │
└────────┬────────────┘
│ __proto__
↓
null
Function 的原型链
JavaScript
// 函数的原型链结构
function Foo() {}
// Foo 是函数,也是 Function 的实例
console.log(Foo.__proto__ === Function.prototype); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true
// Function.prototype 是函数
console.log(typeof Function.prototype); // 'function'
// Function.__proto__ 指向自身
console.log(Function.__proto__ === Function.prototype); // true
获取原型的方法
JavaScript
const obj = {};
// 三种获取原型的方式
console.log(obj.__proto__); // Object.prototype(非标准)
console.log(Object.getPrototypeOf(obj)); // Object.prototype(标准)
console.log(obj.constructor.prototype); // Object.prototype(可能被修改)
// 设置原型
const child = {};
Object.setPrototypeOf(child, { inherited: true });
console.log(child.inherited); // true
// 创建时指定原型
const proto = { greet: 'hello' };
const derived = Object.create(proto);
console.log(derived.__proto__ === proto); // true
原型链终点
JavaScript
// Object.prototype 是原型链终点
const obj = new Object();
console.log(Object.prototype.__proto__); // null
// 所有对象的原型链最终都指向 null
console.log(Object.getPrototypeOf(Object.prototype)); // null
// 检测原型链是否包含某原型
console.log(Object.prototype.isPrototypeOf({})); // true
console.log(Array.prototype.isPrototypeOf([])); // true
console.log(Person.prototype.isPrototypeOf(person)); // true
注意事项
__proto__是非标准属性,生产环境使用Object.getPrototypeOf()- 原型链过长会影响属性查找性能
- 不要在原型上存储可变数据(会被所有实例共享)
text
// 危险:原型上存储可变数据
Person.prototype.friends = ['Alice'];
const p1 = new Person('Tom');
const p2 = new Person('Jerry');
p1.friends.push('Bob');
console.log(p2.friends); // ['Alice', 'Bob'](被污染)
// 正确做法:在构造函数中初始化
function Person(name) {
this.friends = []; // 每个实例独立
}
要点总结
- 每个对象通过
__proto__链接其原型对象 - 原型链查找顺序:自身属性 → 原型链逐级向上 → null 终止
Object.prototype是原型链终点,其__proto__为 null- 函数有
prototype属性,实例的__proto__指向它 - 使用
Object.getPrototypeOf()和Object.setPrototypeOf()操作原型 - 原型属性被所有实例共享,可变数据应放在实例自身
📝 发现内容有误?点击此处直接编辑