创建型-原型模式

创建,原型,模式 · 浏览次数 : 157

小编点评

**原型模式**是一种对象创建型模式,通过原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。 **原型模式的优点:** * 减少了代码重复性。 * 提高了代码的可读性。 * 允许创建指向同一对象的多个实例。 **原型模式的缺点:** * 可能导致内存泄漏。 * 容易出现类继承问题。 **原型模式的使用场景:** * 创建指向同一对象的多个实例。 * 创建与其他对象类似的对象。 * 实现继承。 **原型模式的实现方式:** 1. 创建一个原型对象。 2. 使用原型对象创建新对象。 3. 通过原型链访问新对象的属性和方法。

正文

定义

 使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式---百科。

 通俗的说就是原型模式是一种创建型设计模式,指定某个对象(通过某种方式)得到一个新的对象,在内存中拥有新的地址,得到的对象与原对象是是相互独立的,即得到跟原对象一样的对象

 当我们需要两个一模一样的实例时,使用原型模式非常方便,如果不使用原型模式,按照构造函数的方式初始化对象,我们需要传两次一模一样的参数如:

const dog = new BydCard('byd', '汉', '30w', '2023款')
const dog_copy = new BydCard('byd', '汉', '30w', '2023款')
// 使用原型模式
const dog_copy1 = Object.create(dog)

实现思路

  通过目标对象得到一个全新的新对象,使新对象也具备跟目标对象一样的能力,这种一般思路有两种

  1. 深拷贝
  2. 指针引用:自身对象找不到,通过内部属性引用到目标对象上去找类似链表结构的next 指针

其中大多数后台语言如java 有相关克隆接口规范,javaScript 是通过第二种方式来实现的。

javaScript 中的原型模式

  在原型模式下,当我们想要创建一个对象时,会先找到一个对象作为原型,然后通过克隆原型的方式来创建出一个与原型一样(共享一套数据/方法)的对象。在 JavaScript 里,Object.create方法就是原型模式的天然实现——准确地说,只要我们还在借助Prototype来实现对象的创建和原型的继承,那么我们就是在应用原型模式

  有的设计模式资料中会强调,原型模式就是拷贝出一个新对象,认为在 JavaScript 类里实现了深拷贝方法才算是应用了原型模式。事实上在 JavaScript 中,通过指针的方式也可以得到目标对象、属性、方法的共享。克隆(深度拷贝)是实现这个目的的方法,但不是唯一的方法,也不是javaScript 的目的。

通过指针来引用,然后动态执行的时候绑定上下文 this,这样就不会造成实例之间的错乱,我觉得这也是this 被设计成动态绑定的原因之一。

原型模式-编程范式

  原型模式不仅是一种设计模式,它还是一种编程范式(programming paradigm),是 JavaScript 面向对象系统实现的根基,原型编程范式的体现就是基于原型链的继承。即便现在es6+ 推出了class 关键字,支持了类的写法。引入的 JavaScript 类本质上还是基于原型的继承的语法糖(class 只是一个语法糖)。类语法不会为 JavaScript 引入新的面向对象的继承模型。 当我们尝试用 class 去定义一个 Dog 类时:

class Dog {
  constructor(name ,age) {
   this.name = name
   this.age = age
  }
  
  eat() {
    console.log('肉骨头真好吃')
  }
}

其实完全等价于写了这么一个构造函数:

function Dog(name, age) {
  this.name = name
  this.age = age
}
Dog.prototype.eat = function() {
  console.log('肉骨头真好吃')
}

原型链核心点

  每个构造函数都拥有一个prototype属性,它指向构造函数的原型对象,这个原型对象中有一个 constructor 属性指回构造函数;每个实例都有一个内部属性__proto__属性,当我们使用构造函数去创建实例时,实例的__proto__属性就会指向构造函数的原型对象。

// 输出"肉骨头真好吃"
dog.eat()
// 输出"[object Object]"
dog.toString()

明明没有在 dog 实例里手动定义 eat 方法和 toString 方法,它们还是被成功地调用了。这是因为当我试图访问一个 JavaScript 实例的属性、方法时,它首先搜索这个实例本身;当发现实例没有定义对应的属性、方法时,它会转而去搜索实例的原型对象;如果原型对象中也搜索不到,它就去搜索原型对象的原型对象,这个搜索的链表就叫做原型链

Object 是所有的基类,其中Object.prototype指向null,这样原型链就有终点了,而不是无脑的一直下去。

原型链其他关键点:

  1. 所有函数(普通函数,构造函数,内置的函数)都是内置函数(类)Function 的实例,所以存在函数.__proto__ === Function.prototype 所有函数都可以直接调用Function原型上的方法(call / apply /bind)
  2. Function 确实很厉害,他不仅是函数的类,还是自己的类。函数是Function 的实例,Function 也是Function 的实例 Object.__proto__ === Function.prototypeFunction.__proto__===Function.prototype
  3. 对象的原型链最终指向Object.prototype, object.prototype._proto_ 指向null

如下代码验证了这些结论:

function sayHi () {
    // console.log('hello joel')
}

// 所有函数都是Function 的实例即函数也是对象,
// 所以存在函数.__proto__ === Function.prototype
console.log(sayHi.__proto__ === Function.prototype) // true
console.log(Object.__proto__ === Function.prototype) // true
console.log(String.__proto__ === Function.prototype) // true
console.log(Array.__proto__ === Function.prototype) // true
console.log(Number.__proto__ === Function.prototype) // true
console.log(Symbol.__proto__ === Function.prototype) // true

// Function.prototype 内部属性又指向Object的原型对象
console.log(Function.prototype.__proto__ === Object.prototype) // true
//  Function 也是Function 的实例
console.log(Function.__proto__ === Function.prototype)
// 对象最终指向object的原型
console.log(new sayHi().__proto__ instanceof Object) // true
console.log(new sayHi().__proto__ === sayHi.prototype) // true
console.log(Array.prototype.__proto__ === Object.prototype) // true
console.log(Object.__proto__.__proto__ === Object.prototype) // true

// 内置的array,string,number,object 等都是构造函数,同时也是对象
console.log(typeof Array) // function
console.log(typeof Object) // function

// 通过原型链找到object.prototype 上的方法
sayHi.valueOf() 

小结

  1. 原型是 JavaScript 面向对象系统实现的根基,在这里更像是一种编程范式
  2. 在JavaScript 中原型模式无处不在,只要使用原型的模型创建对象就是在使用原型模式
Object.__proto__ === Function.prototype
Function.__proto__=== Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__prto__ === null

 

与创建型-原型模式相似的内容:

创建型-原型模式

定义 使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式 百科。 通俗的说就是原型模式是一种创建型设计模式,指定某个对象(通过某种方式)得到一个新的对象,在内存中拥有新的地址,得到的对象与原对象是是相互独立的,即得到跟原对象一样的对象 当我们需要两个一模一

Prototype 原型模式简介与 C# 示例【创建型4】【设计模式来了_4】

通过简单的示例代码,来介绍原型设计模式的特点与适用场景等。

软件设计模式系列之七——原型模式

原型模式(Prototype Pattern)是一种创建型设计模式,其主要目的是通过复制现有对象来创建新对象,而不是使用构造函数。原型模式将对象的创建委托给原型对象,通过克隆(复制)来生成新对象,这种方式可以避免对象的重复初始化,提高性能,并使对象的创建更加灵活和动态。

设计模式学习(五):原型模式

设计模式学习(五):原型模式 作者:Grey 原文地址: 博客园:设计模式学习(五):原型模式 CSDN:设计模式学习(五):原型模式 原型模式 原型模式是创建型模式。 如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段的值都相同),在这种情况下,我们可以利用对已有对象(原型)进

创建型:工厂模式-工厂方法、抽象工厂

简单工厂问题 简单工厂中我们通过参数来返回不同的产品对象,如果管理的对象过多,这个工厂函数会比较庞大,且当我们需要增加一个新的产品时,需要修改这个工厂方法,违反开闭原则(对拓展开放,对修改关闭)。 为了解决简单工厂模式的问题,出现了工厂方法模式。 解决简单工厂思路 简单工厂类图关系类似如下: 如上图

设计模式之抽象工厂模式(学习笔记)

定义 抽象工厂模式是一种创建型设计模式,它提供一个接口,用于创建一系列相关或依赖的对象,而无需指定它们的具体类。抽象工厂模式将对象的创建过程抽象化,允许子类通过实现具体工厂类来定制对象的创建。 为什么使用抽象工厂模式 产品族的一致性 抽象工厂模式确保同一产品族中的对象之间的一致性。 部分遵循开闭原则

设计模式学习(三):工厂模式

设计模式学习(三):工厂模式 作者:Grey 原文地址: 博客园:设计模式学习(三):工厂模式 CSDN:设计模式学习(三):工厂模式 工厂模式 工厂模式是创建型模式,工厂模式分为:简单工厂,工厂方法和抽象工厂三种类型。 简单工厂 这个模式很简单,比如我们需要制造不同类型的鼠标,我们只需要创建一个鼠

设计模式学习(四):建造者模式

设计模式学习(四):建造者模式 作者:Grey 原文地址: 博客园:设计模式学习(四):建造者模式 CSDN:设计模式学习(四):建造者模式 建造者模式 建造者模式是创建型模式。 我们在对一个实体类进行属性的 get 或 set 的时候,可以通过封装一些常用的构造方法来简化实体类的构造。 比如 Ef

设计模式学习(二):单例模式

设计模式学习(二):单例模式 作者:Grey 原文地址: 博客园:设计模式学习(二):单例模式 CSDN:设计模式学习(二):单例模式 单例模式 单例模式是创建型模式。 单例的定义:“一个类只允许创建唯一一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。”定

【23种设计模式】原型模式(五)

## 前言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这就会增加创建类的复杂度和创建过程与客户代码复杂的耦合度。如果采用工厂模式来创建这样的实例对象的话,随着产品类的不断增加,导致子类的数量不断增多,也导致了相