原型与继承(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); // true

Object.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

🔗 相关链接


参考


javascript 原型 继承 prototype inheritance