原型模式 Prototype
概述
原型模式的定义是用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。通俗一点讲就是拷贝一个新对象。
拷贝通常有浅拷贝和深拷贝,那么js中浅拷贝很容易实现,所以接下来主要用该模式实现深拷贝。
运用
原型模式的角色:
- Prototype:抽象原型角色,抽象类或者接口,用来声明clone方法。
- ConcretePrototype:具体的原型类,是客户端角色使用的对象,即被复制的对象。
Prototype 类
class Prototype {
constructor(prototype) {
console.log("Prototype Class created");
}
setFeature(key, val) {
this[key] = val
}
clone() {
throw new Error("This method must be overwritten!");
}
}
ConcretePrototype 类
class ConcretePrototype1 extends Prototype {
constructor() {
super();
console.log("ConcretePrototype1 created");
this.feature = "feature 1"
}
// 实现深拷贝
clone() {
console.log('ConcretePrototype1.clone invoked');
let clone = new ConcretePrototype1();
let keys = Object.keys(this);
keys.forEach(k => clone.setFeature(k, this[k]));
console.log("ConcretePrototype1 cloned");
return clone;
}
}
class ConcretePrototype2 extends Prototype {
constructor() {
super();
console.log("ConcretePrototype2 created");
this.feature = "feature 2"
}
// 实现深拷贝
clone() {
console.log('ConcretePrototype2.Clone function');
let clone = new ConcretePrototype2();
let keys = Object.keys(this);
keys.forEach(k => clone.setFeature(k, this[k]));
console.log("ConcretePrototype2 cloned");
return clone;
}
}
上述 ConcretePrototype1 和 ConcretePrototype2 就是客户使用的普通对象,原型模式中让一个普通对象拷贝一个自己,仅需要继承 Prototype 类,重写 clone 方法即可。
测试一下
let proto1 = new ConcretePrototype1();
proto1.setFeature('feature', "feature 11");
let clone1 = proto1.clone();
console.log(clone1.feature);
console.log(typeof clone1);
console.log(clone1 === proto1); // 深拷贝的对象与原对象不是同一个对象
# 输出如下结果:
# feature 11
# object
# false
let proto2 = new ConcretePrototype2();
proto2.setFeature('feature', "feature 22");
let clone2 = proto2.clone();
console.log(clone2.feature);
console.log(typeof clone2);
console.log(clone2 === proto2);
# 输出如下结果:
# feature 22
# object
# false
总结
适用场景
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。这个通常指浅拷贝。
- 客户需要操作原对象,但又不希望操作影响到原对象,可以对原对象深拷贝出一个新对象来,然后在新对象上进行操作。
优点
- 可以节省使用 new 初始化对象的复杂流程,因为可以完全拷贝一个已初始化好的对象