JS原型(prototype)的介绍

295 阅读2分钟

原型(Prototype)是计算机科学中一个重要的概念,尤其在 JavaScript面向对象编程(OOP) 中具有核心地位。以下是关于原型的详细介绍:


1. 什么是原型?

  • 定义:原型(Prototype)是一个对象,它作为其他对象的模板,提供共享的属性和方法。新对象可以通过继承原型来复用这些属性和方法。
  • 核心思想:基于原型的继承(Prototype-based Inheritance),与基于类的继承(Class-based Inheritance)不同,允许对象直接继承其他对象。

2. JavaScript 中的原型

在 JavaScript 中,每个对象都有一个隐藏的 [[Prototype]] 属性(可通过 __proto__ 访问),指向它的原型对象。当访问对象的属性或方法时,若对象自身不存在该属性,则会沿着原型链(Prototype Chain)向上查找,直到找到或到达原型链的末端(null)。

关键概念:

  • 构造函数(Constructor):通过 new 关键字创建对象的函数。构造函数有一个 prototype 属性,指向其原型对象。
  • 原型对象(Prototype Object):包含共享属性和方法的对象,由构造函数创建的所有实例共同继承。
  • 原型链(Prototype Chain):对象通过 [[Prototype]] 形成的链式结构,用于实现继承。

示例代码:

// 构造函数
function Person(name) {
  this.name = name;
}

// 在原型上添加方法(共享)
Person.prototype.sayHello = function() {
  console.log(`Hello, I'm ${this.name}`);
};

// 创建实例
const alice = new Person("Alice");
alice.sayHello(); // "Hello, I'm Alice"

// 原型链:alice -> Person.prototype -> Object.prototype -> null

3. 原型继承的机制

  1. 构造函数与原型的关系

    • 构造函数的 prototype 属性指向原型对象。
    • 原型对象的 constructor 属性指回构造函数。
    • 实例的 __proto__ 指向构造函数的 prototype
    Person.prototype.constructor === Person; // true
    alice.__proto__ === Person.prototype;    // true
    
  2. 属性查找规则

    • 当访问 alice.sayHello() 时,先在实例自身查找。
    • 若未找到,则通过 alice.__proto__ 查找 Person.prototype
    • 若仍未找到,继续沿着原型链向上查找,直到 Object.prototypenull

4. 原型链的终点

  • 所有对象的原型链最终指向 Object.prototype,而 Object.prototype.__proto__null
  • 例如:alice.__proto__.__proto__ === Object.prototype(true)。

5. 修改原型

  • 动态性:JavaScript 的原型是动态的,修改原型对象会立即影响所有实例。
    Person.prototype.sayBye = function() { console.log("Bye!") };
    alice.sayBye(); // 新增方法对所有实例生效
    
  • 覆盖原型:直接替换 prototype 会断开已有实例与原型的联系。
    Person.prototype = { newMethod() {} };
    const bob = new Person("Bob");
    bob.sayHello(); // 报错,旧方法已丢失
    

6. 原型继承的优缺点

优点

  • 内存高效:共享方法只需定义一次,所有实例复用。
  • 灵活性:动态修改原型,扩展功能方便。

缺点

  • 共享引用类型属性:若原型包含引用类型(如数组),所有实例会共享同一份数据。
  • 性能问题:过长的原型链可能影响查找速度。

7. ES6 中的 class 语法

ES6 引入了 class 关键字,但其本质仍是基于原型的语法糖:

class Person {
  constructor(name) { this.name = name; }
  sayHello() { console.log(`Hello, I'm ${this.name}`); }
}

typeof Person; // "function"(类本质是函数)

8. 其他应用场景

  • 原型模式:设计模式中,通过克隆原型对象创建新对象,避免重复初始化。
  • 原型工具方法:如 Object.create() 直接基于原型创建对象:
    const animal = { eats: true };
    const rabbit = Object.create(animal);
    console.log(rabbit.eats); // true
    

总结

原型是 JavaScript 实现继承和共享行为的核心机制。理解原型链、构造函数与原型对象的关系,是掌握 JavaScript 面向对象编程的关键。通过合理使用原型,可以写出高效、灵活的代码,同时避免共享数据导致的意外问题。