跳到主要内容

原型与原型链

介绍

在 JavaScript 中,原型(Prototype)原型链(Prototype Chain) 是理解对象继承机制的关键概念。JavaScript 是一种基于原型的语言,这意味着对象可以通过原型继承属性和方法,而不是通过传统的类继承。

本文将逐步讲解原型与原型链的概念,并通过代码示例和实际案例帮助你更好地理解它们的工作原理。


什么是原型?

在 JavaScript 中,每个对象都有一个内部属性 [[Prototype]],它指向另一个对象,称为该对象的原型。原型对象本身也可以有自己的原型,从而形成一条链,称为 原型链

原型的作用

  • 共享属性和方法:原型允许对象共享属性和方法,从而节省内存。
  • 实现继承:通过原型链,对象可以继承其原型的属性和方法。

访问原型

在 JavaScript 中,可以通过以下方式访问对象的原型:

  1. 使用 Object.getPrototypeOf(obj) 方法。
  2. 使用 obj.__proto__ 属性(非标准,但广泛支持)。
javascript
const person = {
name: "Alice",
greet() {
console.log(`Hello, my name is ${this.name}`);
},
};

const student = Object.create(person);
student.name = "Bob";

console.log(Object.getPrototypeOf(student) === person); // true
console.log(student.__proto__ === person); // true

原型链

原型链是由对象的原型组成的链式结构。当访问一个对象的属性或方法时,JavaScript 会沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的顶端(null)。

原型链的工作原理

  1. 当访问对象的属性或方法时,JavaScript 首先在对象自身查找。
  2. 如果未找到,则继续在其原型对象中查找。
  3. 如果仍未找到,则继续在原型的原型中查找,直到找到或到达 null
javascript
const animal = {
sound: "Unknown",
makeSound() {
console.log(this.sound);
},
};

const dog = Object.create(animal);
dog.sound = "Woof";

const puppy = Object.create(dog);

puppy.makeSound(); // 输出: Woof

在上面的例子中,puppy 对象本身没有 makeSound 方法,但它通过原型链继承了 dogmakeSound 方法。


构造函数与原型

在 JavaScript 中,构造函数通常用于创建对象。每个构造函数都有一个 prototype 属性,指向一个对象。当使用 new 关键字调用构造函数时,新创建的对象的 [[Prototype]] 会指向构造函数的 prototype 属性。

javascript
function Person(name) {
this.name = name;
}

Person.prototype.greet = function () {
console.log(`Hello, my name is ${this.name}`);
};

const alice = new Person("Alice");
alice.greet(); // 输出: Hello, my name is Alice
提示

构造函数的 prototype 属性是一个对象,它包含所有实例共享的属性和方法。


实际案例:实现继承

原型链的一个重要应用是实现对象之间的继承。以下是一个简单的继承示例:

javascript
function Animal(name) {
this.name = name;
}

Animal.prototype.makeSound = function () {
console.log(`${this.name} makes a sound`);
};

function Dog(name) {
Animal.call(this, name); // 调用父类构造函数
}

// 设置 Dog 的原型为 Animal 的实例
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function () {
console.log(`${this.name} barks`);
};

const dog = new Dog("Buddy");
dog.makeSound(); // 输出: Buddy makes a sound
dog.bark(); // 输出: Buddy barks

在这个例子中,Dog 继承了 Animal 的属性和方法,并添加了自己的方法 bark


总结

  • 原型 是 JavaScript 中对象继承的基础,每个对象都有一个原型。
  • 原型链 是由对象的原型组成的链式结构,用于查找属性和方法。
  • 通过 构造函数prototype 属性,可以实现对象之间的继承。

理解原型与原型链是掌握 JavaScript 面向对象编程的关键。希望本文能帮助你更好地理解这些概念,并在实际开发中灵活运用。


附加资源与练习

资源

练习

  1. 创建一个 Cat 构造函数,使其继承 Animal,并添加一个 meow 方法。
  2. 使用 Object.create 实现一个简单的对象继承链。
  3. 尝试修改一个对象的原型,并观察其对其他对象的影响。
警告

修改对象的原型可能会影响所有继承自该原型的对象,请谨慎操作。