JavaScript原型模式详解

113 阅读3分钟

什么是原型模式?

原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制(克隆)现有对象来创建新对象,而不是通过实例化类。在JavaScript中,这种模式尤其重要,因为JavaScript本身就是基于原型的语言。

在原型模式下,当我们想要创建一个对象时,会先找到一个对象作为原型,然后通过克隆原型的方式来创建出一个与原型一样(共享一套数据/方法)的对象。Object.create方法就是原型模式的天然实现。

基础实现

// 创建一个原型对象
const userPrototype = {
    name: '默认用户',
    sayHello() {
        console.log(`你好,我是${this.name}`);
    },
    clone() {
        // 基于当前对象创建新对象
        return Object.create(this);
    }
};

// 使用原型创建新对象
const user1 = userPrototype.clone();
user1.name = '张三';
user1.sayHello(); // 输出:你好,我是张三

const user2 = userPrototype.clone();
user2.name = '李四';
user2.sayHello(); // 输出:你好,我是李四

JavaScript的原型机制

在 JavaScript 中,每个构造函数都拥有一个prototype属性,它指向构造函数的原型对象,这个原型对象中有一个 constructor 属性指回构造函数;每个实例都有一个__proto__属性,当我们使用构造函数去创建实例时,实例的__proto__属性就会指向构造函数的原型对象。 让我用一个具体的例子来解释这个概念:

  • 构造函数 :定义对象的创建过程
  • 原型对象(prototype) :存储共享的属性和方法
  • 实例 :基于原型创建的具体对象
// 1. 构造函数
function Person(name) {
    this.name = name;
}

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

// 3. 创建实例
const person = new Person('张三');

让我们逐步分析这个关系:

  1. 构造函数与prototype
console.log('Person的原型对象:',Person.prototype); // Person的原型对象
console.log(Person.prototype.constructor === Person); // true

Snipaste_2025-05-06_15-26-58.png

  • 每个构造函数(Person)都有一个 prototype 属性
  • 这个 prototype 属性指向构造函数的原型对象
  • 原型对象中有一个 constructor 属性指回构造函数
  1. 实例与__proto__
console.log(person.__proto__ === Person.prototype); // true
  • 每个实例(person)都有一个 proto 属性
  • 这个 proto 属性指向构造函数的原型对象
  1. 图解说明

image.png

  1. 实际应用示例
// 通过原型链查找属性
console.log(person.sayHello); // 找到原型上的方法
console.log(person.hasOwnProperty('name')); // true,自身属性
console.log(person.hasOwnProperty('sayHello')); // false,原型上的方法

JavaScript的原型本质【拓展】

该如何理解【JavaScript作为基于原型的语言】这句话,接下来我从4个方面简单举例说明:

  1. 对象的创建机制: 在JavaScript中,对象的创建不是基于类(Class),而是基于原型(Prototype)
// 传统的基于类的语言(如Java)
class Animal {
    constructor(name) {
        this.name = name;
    }
}
const dog = new Animal('小黑');

// JavaScript的原型方式
const animal = {
    name: '',
    eat() {
        console.log(`${this.name}正在吃东西`);
    }
};
const dog = Object.create(animal);
dog.name = '小黑';
  1. 继承的实现方式: JavaScript通过原型链实现继承,而不是类继承
// 原型链继承
const parent = {
    lastName: '张'
};

const child = Object.create(parent);
child.firstName = '小明';

console.log(child.lastName); // 输出:张
  1. 动态性:JavaScript的原型系统允许在运行时动态修改对象的行为
// 动态添加方法
Object.prototype.sayHello = function() {
    console.log('Hello!');
};

const obj = {};
obj.sayHello(); // 所有对象都能调用这个方法
  1. 原生对象也基于原型:JavaScript的所有内置对象都是基于原型实现的
// 数组继承自Array.prototype
const arr = [];
console.log(arr.__proto__ === Array.prototype); // true

// 函数继承自Function.prototype
function foo() {}
console.log(foo.__proto__ === Function.prototype); // true

实际应用场景

组件复用

const baseComponent = {
    render() { /* 渲染逻辑 */ },
    mount() { /* 挂载逻辑 */ },
    unmount() { /* 卸载逻辑 */ }
};

const button = Object.create(baseComponent);
const input = Object.create(baseComponent);

配置对象

const defaultConfig = {
    theme: 'light',
    fontSize: 14,
    language: 'zh-CN'
};

const darkConfig = Object.create(defaultConfig);
darkConfig.theme = 'dark';

总结与思考

原型模式作为JavaScript面向对象编程的基石,不仅提供了一种高效的对象创建机制,更体现了JavaScript语言设计的精髓。通过原型系统,我们能够实现对象的继承、属性的共享以及行为的动态扩展,这种灵活而强大的机制让JavaScript在处理复杂的Web应用时显得游刃有余。深入理解原型模式,不仅能帮助我们写出更优雅的代码,也能让我们更好地把握JavaScript这门语言的本质。让我们在实践中不断探索和运用这一强大的设计模式,创造出更多优秀的应用!