设计模式:创建型-原型模式
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 // true
dog.__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;
}
实现深拷贝时,若属性为值类型,则直接返回;如属性为引用类型,则递归遍历。
以上是关于设计模式:创建型-原型模式的主要内容,如果未能解决你的问题,请参考以下文章