javascript开发人员对prototype这个东西恐怕都十分熟悉了,可是对于prototype模式了解的人恐怕不是很多。
原型模式的用意是:通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的办法创建出更多的同类型对象。
和其他创建型模式不同:prototype模式创建对象不是通过new一个类,而是通过一个现有的对象实例来的。有经验的编程人员应该都接触过对象的clone方法,这就是原型模式的应用。

很多文章关于生活中原型模式的例子,用的是细胞的分裂来描述,是比较贴切的。
下面是一个比较实际的web应用中的例子,通过现有的dom元素对象,创建了一个新的副本。这个副本dom元素并没有使用document.createElement方法创建。
<body>
<div id="test">TestDiv</div>
</body>
<script>
var testClone = document.getElementById('test').cloneNode(true);
document.body.appendChild(testClone);
</script>
原型模式通过拷贝对象成员来创建新的对象。这个过程分为两种情况:浅拷贝和深拷贝。
当对象执行了浅拷贝,新对象和原对象中,引用类型成员仍然指向同一个地址,修改操作可能相互影响。
当对象执行了深拷贝,新对象和原对象就没有任何共享的东西,任何一个对象的修改不会影响到另外一个对象。

浅拷贝示例:
function Writer (name, sex) {
    this.name = name;
    this.sex = sex;
}
function Book (name, pages, price, writer) {
    this.name = name;
    this.pages = pages;
    this.price = price;
    this.writer = writer;
}
Book.prototype.clone = function () {//深拷贝浅拷贝的区别就在这个function里
    return new Book(this.name,
                        this.pages,
                        this.price,
                        this.writer);
}
var writer = new Writer('谭振林', '男');
var bookName = '深入解析ASP.NET控件开发';
var myBook = new Book(bookName, 611, 70, writer);
var otherBook = myBook.clone();
myBook.name = '不是深入解析ASP.NET控件开发';    //值类型的修改不会相互影响
alert([myBook.name,otherBook.name]);//所以这里打印:不是深入解析ASP.NET控件开发,深入解析ASP.NET控件开发
myBook.writer.name = '不是谭震林';    //引用类型的修改会相互影响,因为他们引用同个内存地址
alert([myBook.writer.name, otherBook.writer.name]);//所以这里打印:不是谭震林,不是谭震林


深拷贝示例:
function Writer (name, sex) {
    this.name = name;
    this.sex = sex;
}
function Book (name, pages, price, writer) {
    this.name = name;
    this.pages = pages;
    this.price = price;
    this.writer = writer;
}
Book.prototype.clone = function () {//深拷贝浅拷贝的区别就在这个function里
    var writer = new Writer(this.writer.name,this.writer.sex);
    return new Book(this.name,
                        this.pages,
                        this.price,
                        writer);
}
var writer = new Writer('谭振林', '男');
var bookName = '深入解析ASP.NET控件开发';
var myBook = new Book(bookName, 611, 70, writer);
var otherBook = myBook.clone();
myBook.name = '不是深入解析ASP.NET控件开发';    //值类型的修改不会相互影响
alert([myBook.name,otherBook.name]);//所以这里打印:不是深入解析ASP.NET控件开发,深入解析ASP.NET控件开发
myBook.writer.name = '不是谭震林';    //深拷贝,引用已经指向不同内存地址,修改不会相互影响
alert([myBook.writer.name, otherBook.writer.name]);//所以这里打印:不是谭震林,谭震林

这里顺带说明一下,javascript中的面向对象机制是通过prototype实现的,在new一个对象的时候,其实并没有为每一个对象创建每个prototype成员的副本,而是将对象成员指针指向prototype成员,下面程序可以验证这点:
function Test () {
}
Test.prototype.alert = function () {
    alert('test');
}
var test1 = new Test();
var test2 = new Test();
alert(test1.alert === test2.alert);
test1.constructor.prototype.alert = function () {alert('test1');}
test2.alert();
说的白一点,prototype模式就是用来(通过)复制(创建)对象的。那我们什么时候应该使用prototype模式呢?我认为:
1.当你要创建的对象与现有运行时对象相似度很大时
2.为了避免创建类的工厂类导致层次复杂度增加时
3.当类的实例只有不多的几种状态时(此时需要引进原型管理器)

关于少量状态时引入原型管理器引导对象的创建,实例如下:
<div id="styletest">StyleTest</div>
<script>
//类定义
function StyleItem (fontSize, color) {
    this.fontSize = fontSize;
    this.color = color;
}
StyleItem.prototype.clone = function () {
    return {
        fontSize:this.fontSize,
        color:this.color
    }
}
//原型管理器
var StyleManager = {
    getStyle: function (key) {
        if (this[key]) {
            return this[key].clone();
        }
    }
};
//预创建类可能的状态集合对象
StyleManager['big'] = new StyleItem('16px', '#000');
StyleManager['normal'] = new StyleItem('14px', '#333');
StyleManager['small'] = new StyleItem('12px', '#666');

//无需再通过new来创建StyleItem类的对象了
var el = document.getElementById('styletest');
var style = StyleManager.getStyle('small');
for (var k in style)el.style[k] = style[k];
</script>

转自http://www.cnblogs.com/iloveu/archive/2009/03/31/1426200.html

 posted on 2010-06-08 09:41  chao_yu  阅读(864)  评论(0编辑  收藏  举报