跳转到内容

原型与原型链

来自代码酷

原型与原型链[编辑 | 编辑源代码]

原型(Prototype)原型链(Prototype Chain)是 JavaScript 中实现继承的核心机制,理解它们对于掌握 JavaScript 的面向对象编程至关重要。本文将详细介绍原型、原型链的概念、工作原理及其实际应用。

介绍[编辑 | 编辑源代码]

在 JavaScript 中,每个对象(除了 null)都有一个与之关联的原型对象(Prototype)。原型对象本身也是一个对象,它包含可以被其他对象继承的属性和方法。当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或方法,或者到达原型链的顶端(null)。

原型(Prototype)[编辑 | 编辑源代码]

构造函数的 prototype 属性[编辑 | 编辑源代码]

在 JavaScript 中,每个函数都有一个 prototype 属性(仅函数有),它指向一个对象,该对象是实例对象的原型。

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

// 为 Person 的原型添加方法
Person.prototype.sayHello = function() {
    console.log(`Hello, my name is ${this.name}`);
};

const person1 = new Person("Alice");
person1.sayHello(); // 输出:Hello, my name is Alice
  • Person.prototypeperson1 的原型对象。
  • person1.__proto__(非标准属性,但浏览器支持)也指向 Person.prototype

对象的 __proto__ 属性[编辑 | 编辑源代码]

每个对象都有一个 __proto__ 属性(非标准,但广泛支持),指向其构造函数的 prototype 对象。

console.log(person1.__proto__ === Person.prototype); // 输出:true

原型链(Prototype Chain)[编辑 | 编辑源代码]

原型链是由对象的 __proto__ 属性串联起来的链式结构。当访问一个对象的属性或方法时,JavaScript 会沿着原型链向上查找。

示例[编辑 | 编辑源代码]

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

Animal.prototype.eat = function() {
    console.log(`${this.name} is eating.`);
};

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

// 设置 Dog.prototype 的原型为 Animal.prototype
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复 constructor 指向

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

const dog1 = new Dog("Buddy", "Golden Retriever");
dog1.eat(); // 输出:Buddy is eating.
dog1.bark(); // 输出:Buddy is barking!

原型链图示[编辑 | 编辑源代码]

graph LR dog1 -->|__proto__| Dog.prototype Dog.prototype -->|__proto__| Animal.prototype Animal.prototype -->|__proto__| Object.prototype Object.prototype -->|__proto__| null

  • dog1.__proto__ 指向 Dog.prototype
  • Dog.prototype.__proto__ 指向 Animal.prototype
  • Animal.prototype.__proto__ 指向 Object.prototype
  • Object.prototype.__proto__null,表示原型链的终点。

实际应用[编辑 | 编辑源代码]

继承的实现[编辑 | 编辑源代码]

原型链是 JavaScript 实现继承的基础。通过修改原型链,可以实现类似传统面向对象语言中的继承。

// 使用 ES6 的 class 语法(底层仍基于原型)
class Animal {
    constructor(name) {
        this.name = name;
    }
    eat() {
        console.log(`${this.name} is eating.`);
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name);
        this.breed = breed;
    }
    bark() {
        console.log(`${this.name} is barking!`);
    }
}

const dog2 = new Dog("Max", "Labrador");
dog2.eat(); // 输出:Max is eating.
dog2.bark(); // 输出:Max is barking!

内置对象的原型[编辑 | 编辑源代码]

JavaScript 的内置对象(如 ArrayString)也通过原型链扩展方法。

const arr = [1, 2, 3];
console.log(arr.__proto__ === Array.prototype); // 输出:true
console.log(Array.prototype.__proto__ === Object.prototype); // 输出:true

常见问题[编辑 | 编辑源代码]

如何判断属性是自身的还是继承的?[编辑 | 编辑源代码]

使用 hasOwnProperty 方法:

console.log(dog1.hasOwnProperty("name")); // 输出:true
console.log(dog1.hasOwnProperty("eat")); // 输出:false

如何获取对象的原型?[编辑 | 编辑源代码]

  • 非标准方式:obj.__proto__
  • 标准方式:Object.getPrototypeOf(obj)
console.log(Object.getPrototypeOf(dog1) === Dog.prototype); // 输出:true

总结[编辑 | 编辑源代码]

  • 每个对象都有一个原型(__proto__),构造函数的 prototype 是实例的原型。
  • 原型链是对象通过 __proto__ 连接起来的链式结构,用于实现属性和方法的继承。
  • 原型链的顶端是 Object.prototype,其 __proto__null
  • 实际开发中,可以使用 classextends 语法简化继承的实现。