原型与继承(Prototype & Inheritance)
JavaScript 基于原型的继承机制。
📚 原型链(Prototype Chain)
原型对象
每个对象都有一个内部属性 [[Prototype]](可通过 __proto__ 或 Object.getPrototypeOf() 访问):
const obj = {};
console.log(obj.__proto__ === Object.prototype); // true
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true原型链查找
const obj = {};
obj.toString(); // 从 Object.prototype 继承
// 查找过程:
// 1. obj 自身是否有 toString?
// 2. obj.__proto__ (Object.prototype) 是否有 toString?
// 3. 找到,调用🎯 构造函数与原型
构造函数创建对象
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `Hello, I'm ${this.name}`;
};
const person = new Person('Alice');
console.log(person.greet()); // "Hello, I'm Alice"原型关系
function Person(name) {
this.name = name;
}
const person = new Person('Alice');
// 原型关系
console.log(person.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true(原型链终点)🔄 继承实现
1. 原型链继承
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
return `${this.name} makes a sound`;
};
function Dog(name, breed) {
Animal.call(this, name); // 调用父构造函数
this.breed = breed;
}
// 继承原型
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {
return `${this.name} barks`;
};
const dog = new Dog('Buddy', 'Golden Retriever');
console.log(dog.speak()); // "Buddy barks"2. ES6 类继承
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a sound`;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
speak() {
return `${this.name} barks`;
}
}🔍 原型方法
Object.create()
const animal = {
speak() {
return 'makes a sound';
}
};
const dog = Object.create(animal);
dog.name = 'Buddy';
console.log(dog.speak()); // "makes a sound"Object.getPrototypeOf()
const obj = {};
console.log(Object.getPrototypeOf(obj) === Object.prototype); // trueObject.setPrototypeOf()
const animal = { speak() { return 'sound'; } };
const dog = {};
Object.setPrototypeOf(dog, animal);
console.log(dog.speak()); // "sound"hasOwnProperty()
const obj = { name: 'Alice' };
obj.__proto__.age = 30;
console.log(obj.hasOwnProperty('name')); // true(自有属性)
console.log(obj.hasOwnProperty('age')); // false(继承属性)💡 原型模式
1. 共享方法
function Person(name) {
this.name = name;
}
// 所有实例共享同一个方法
Person.prototype.greet = function() {
return `Hello, I'm ${this.name}`;
};
const p1 = new Person('Alice');
const p2 = new Person('Bob');
console.log(p1.greet === p2.greet); // true(同一个方法)2. 修改原型影响所有实例
function Person(name) {
this.name = name;
}
const p1 = new Person('Alice');
const p2 = new Person('Bob');
// 修改原型
Person.prototype.greet = function() {
return `Hi, I'm ${this.name}`;
};
console.log(p1.greet()); // "Hi, I'm Alice"(受影响)
console.log(p2.greet()); // "Hi, I'm Bob"(受影响)⚠️ 注意事项
1. 不要直接修改内置对象原型
// ❌ 不推荐:修改内置对象原型
Array.prototype.sum = function() {
return this.reduce((a, b) => a + b, 0);
};
// ✅ 推荐:使用工具函数或扩展类
class MyArray extends Array {
sum() {
return this.reduce((a, b) => a + b, 0);
}
}2. 原型链查找性能
// 深层原型链会影响性能
// 尽量将常用属性放在对象自身3. 原型污染
// 注意避免原型污染攻击
const userInput = JSON.parse('{"__proto__":{"isAdmin":true}}');
// 可能污染 Object.prototype🔗 相关链接
参考: