一.原型模式
以现有的对象为原型,通过clone得到新的对象(以简化新对象的创建过程)
(引自黯羽轻扬:设计模式总结(《Head First设计模式》学习总结))
和继承很像,把原型模式继续增强就是继承了。原型模式只关心属性复制,而继承除了实现属性复制外还要保证父/子类型的层级关系
二.具体实现
1.基本原理
// 生孩子函数
function beget(obj) {
var F = function() {};
F.prototype = obj;
return new F();
}
// test
var obj = {
attr: 1,
fun: function() {
console.log(this.attr);
}
}
var cp_obj = beget(obj);
cp_obj.fun(); // 1
核心就是beget
函数,把传入的对象塞进空构造函数原型里,创建对象并返回,仅此而已
有一个明显的缺点:来自原型对象(在此例中是obj
)的属性可能会被不小心覆盖掉
P.S.原型对象obj
可以是以任何方式创建的对象,在此例中是对象字面量,当然也可以是new出来的,可以是beget出来的等等
2.简单增强
ES5支持Object.create
函数获取浅拷贝的对象,可以直接把beget
换成:
Object.create(obj);
结果完全一样,因为Object.create
内部实现就是受到道格拉斯原型模式的启发,此外Object.create
还可以有第二个参数,用来定义属性:
Object.create(obj, {
attr: {
value: 2,
writable: false, // 默认值
configurable: false, // 默认值
enumerable: true
}
});
其实就是把Object.create
和Object.defineProperty
合在一起了,例如:
// test
var obj = {
attr: 1,
fun: function() {
console.log(this.attr);
}
}
var cp_obj = Object.create(obj, {
attr2: {
value: 2,
writable: false, // 默认值
configurable: false, // 默认值
enumerable: true
}
});
cp_obj.fun(); // 1
console.log(cp_obj.attr2); // 2
cp_obj.attr2 = 3;
console.log(cp_obj.attr2); // 2,不可写
当然,Object.defineProperty
也是ES5才支持,所以配合使用算是一种增强(访问控制)
三.原型模式的好处
书上有一句很不错的话:
使用Prototype模式的其中一个好处是,我们获得的是JavaScript其本身所具有的原型优势,而不是试图模仿其他语言的特性。
用Java实现的原型模式看起来很怪异,因为就原型模式本身而言,Java中的Object.clone
就可以满足需要了,其它任何形式的实现都显得多余,而JavaScript最初没有提供clone
原生实现(ES5的Object.create
算是弥补了这个缺陷),所以需要原型模式,ES5投入生产之后就不需要手动实现什么原型模式了
更多关于原型模式的介绍请查看23种设计模式(5):原型模式
参考资料
《JavaScript设计模式》