设计模式:创建型-原型模式

Posted 辛月久

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式:创建型-原型模式相关的知识,希望对你有一定的参考价值。

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。这种模式被称为原型模式。


原型模式不仅是一种设计模式,还是一种编程范式,是javascript实现面向对象的根基。


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


JavaScript中的“类”


ECMAScript2015中引入的JavaScript类实质上是JavaScript现有的基于原型的继承的语法糖。类语法不会为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('骨头真好吃');}

所以说啊,JavaScript这个语言的根本就是原型模式。因此我们不必把原型模式当作一种设计模式去理解,把它当作一种编程范式来讨论更合适。



原型与原型链


原型

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

具体来说,当我们使用这样一个构造函数创建一个对象时:

function Dog (name, age) { this.name = name;  this.age = age;}Dog.prototype.eat = function () {  console.log('骨头真好吃');}
const dog = new Dog('旺财',3);

   这段代码里的几个对象就存在这样的关系:


Dog.prototype.constructor === Dog // truedog.__proto__ === Dog.prototype // true


原型链


现在我们在上面那段代码的基础上,进行两个方法调用:

dog.eat(); // 骨头真好吃dog.toString(); // [object Object]

明明我们没有在dog实例里定义eat和toString方法,但他们还是被成功调用了。这是因为当我们试图访问一个实例的属性和方法时,它首先检索这个实例本身;当发现实例没有定义时,会转而去搜索实例的原型对象,如果原型对象还没有,它就去搜索原型对象的原型对象,这个检索的轨迹就是原型链。


以我们的代码为例,它的检索过程是这样的:

图上这些彼此相连的prototype,就组成了一个原型链。注:几乎所有的JavaScript对象都是原型链顶端Object的实例,除了Object.prototype以及如果我们手动用Object.create(null)创建一个没有任何原型的对象,这两个都不属于Object的实例。


对象的深拷贝


面试中常常会遇到的一个问题: 请实现js的深拷贝?


深拷贝没有完美解决方案,每一种方案都有它的边界。面试官考察这题,多数情况下是想测验你对递归的熟练程度:

function deepClone (obj) {  // 如果是值类型或者null,直接return  if(typeof obj !== 'object' || obj === null) {    return obj;  }  // 定义结果对象  let copy = {};    // 如果对象是数组,则定义结果数组  if(obj.constructor === Array) {   copy = [];  }  // 遍历对象的key  for (let key in obj) {    // 如果key是对象的自有属性    if(obj.hasOwnProperty(key)){      // 递归调用深拷贝方法      copy[key] = deepClone(obj[key]);    }  }  return copy;}

实现深拷贝时,若属性为值类型,则直接返回;如属性为引用类型,则递归遍历。



以上是关于设计模式:创建型-原型模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式 - 创建型模式_原型模式

设计模式-创建型-原型模式

原型模式(Prototype)-创建型(Creational)设计模式

创建型设计模式之原型模式

扎实基础_设计模式_创建型_原型模式

扎实基础_设计模式_创建型_原型模式