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

参考书籍:JavaScript设计模式
原型模式就是将原型对象指向创建对象的类,使这些类共享原型对象的方法和属性。在javascript中 是基于原型链实现对象之间的继承,这种继承是基于一种对方法或者属性的共享而不是复制
比如,假设页面中有很多焦点图(网页中常见的图片轮播,切换效果),那么我们要实现这些焦点图最好的方式就是通过创建对象来一一实现,所以我们就需要有一个焦点图类,如下面LoopImages.

//图片轮播类
var LoopImages = function (imgArr, container) {
    this.imageArray = imgArr;
    this.container = container;
    this.createImage = function () {
        console.log('LoopImages createImage');
    };
    this.changeImage = function () {
        console.log('LoopImages changeImage');
    };

}

如果一个页面中有多个这类焦点图,其切换动画一般是多样化的,有可能是上下切换,左右切换等等,因此创建的轮播图片结构应该是多样化的,切换的效果也应该是多样化的,因此我们应该抽象出一个基类,让不同特效类去继承这个基类,然后对于差异化的需求通过重写这些继承下来的属性或者方法来解决。当然不同的子类之间可能存在不同的结构样式,比如有包含一个左右切换箭头,如下面例子this.arrow = arrow;

//上下滑动切换类
var SlideLoopImg = function (imgArr, container) {
    //构造函数继承图片轮播类
    LoopImages.call(this, imgArr, container);
    //重写方法
    this.changeImage = function () {
        console.log('slideLoopImg changeImage');
    }

}
//渐隐切换类
var FadeLoopImg = function (imgArr, container, arrow) {
    LoopImages.call(this, imgArr, container);
    this.arrow = arrow;
    this.changeImage = function () {
        console.log('FadeLoopImg changeImage');
    }
}

测试

    var fadeImg = new FadeLoopImg(['1', '2', '3'], 'fade', ['l', 'r']);
    fadeImg.changeImage();//FadeLoopImg changeImage
    console.log('fadeImg.imageArray: ' + fadeImg.imageArray);//fadeImg.imageArray: 1,2,3
    var slide = new SlideLoopImg(['11', '21', '31'], 'slid');
    slide.changeImage();//slideLoopImg changeImage
    console.log('slide.imageArray: ' + slide.imageArray);//slide.imageArray: 11,21,31
    console.log('fadeImg.imageArray: ' + fadeImg.imageArray);//fadeImg.imageArray: 1,2,3

上面的这个例子还是存在一些问题,我们先看看基类LoopImages,作为基类是要被子类继承的,那么此时将属性和方法都写在基类的构造函数里会有一些问题,比如每次子类继承都要创建一次父类,假如父类的构造函数中创建时存在很多耗时较长的逻辑,或者说每次初始化都会做一些重复的东西,这样的性能消耗很大。为了提高性能,我们需要有一种共享机制,这样每当创建基类时,对于每次创建的一些简单而又差异化的属性我们可以放在构造函数中,而我们将一些消耗资源比如较大的方法放在基类的原型中,这样就避免很多不必要的消耗。
因此,原型模式就是将可复用,可共享的,耗时大的从基类中提出来然后放在其原型中,再通过组合继承或者寄生组合式继承而将方法和属性继承下来,对于子类中那些需要重写的方法进行重写,这样子类创建的对象即具有子类的属性和方法也共享了基类的原型方法,像下面这样:

//图片轮播类
var LoopImages = function (imgArr, container) {
    this.imageArray = imgArr;
    this.container = container;
};
LoopImages.prototype = {
    createImage: function () {
        console.log('LoopImages createImage');
    },
    changeImage: function () {
        console.log('LoopImages changeImage');
    }
}
//上下滑动切换类
var SlideLoopImg = function (imgArr, container) {
    //构造函数继承图片轮播类
    LoopImages.call(this, imgArr, container);
}
//类式继承
SlideLoopImg.prototype = new LoopImages();
//重写方法
SlideLoopImg.prototype.changeImage = function () {
    console.log('slideLoopImg changeImage');
}
//渐隐切换类
var FadeLoopImg = function (imgArr, container, arrow) {
    LoopImages.call(this, imgArr, container);
    this.arrow = arrow;
};
FadeLoopImg.prototype = new LoopImages();
FadeLoopImg.prototype.createImage = function () {
    console.log('FadeLoopImg createImage');
}

测试

  var fadeImg = new FadeLoopImg(['1', '2', '3'], 'fade', ['l', 'r']);
    fadeImg.changeImage();//LoopImages changeImage
    fadeImg.createImage();//FadeLoopImg createImage
    console.log('fadeImg.imageArray: ' + fadeImg.imageArray);//fadeImg.imageArray: 1,2,3
    var slide = new SlideLoopImg(['11', '21', '31'], 'slid');
    console.log('slide.imageArray: ' + slide.imageArray);//slide.imageArray: 11,21,31
    slide.changeImage();//slideLoopImg changeImage
    slide.createImage();//LoopImages createImage
    fadeImg.imageArray.push('new')
    console.log('slide.imageArray: ' + slide.imageArray);//slide.imageArray: 11,21,31
    console.log('fadeImg.imageArray: ' + fadeImg.imageArray);//fadeImg.imageArray: 1,2,3,new

原型对象是一个共享的对象,那么不论是父类的实例对象或者是子类的继承,都是对它的一个指向引用,所以原型对象才会被共享。那么对原型对象的拓展,不论是子类还是父类的实例对象都会继承下来
如下:
基类中添加原型方法

LoopImages.prototype = {
    createImage: function () {
        console.log('LoopImages createImage');
    },
    changeImage: function () {
        console.log('LoopImages changeImage');
    },
    getImgArrLen: function () {
        return this.imageArray.length;
    }
}

子类中增加原型方法,但不能像基类那样使用,不然会报 TypeError: *** is not a function

FadeLoopImg.prototype.createImage = function () {
    console.log('FadeLoopImg createImage');
};
FadeLoopImg.prototype.getConstainer = function () {
    return this.container
};

测试

 console.log('fadeImg.getConstainer: ' + fadeImg.getConstainer());//fade
    console.log('fadeImg.getImgArrLen: ' + fadeImg.getImgArrLen());//4
    console.log('slide.getImgArrLen: ' + slide.getImgArrLen());//3

不过原型模式更多的是用在对对象的创建上,比如创建一个实例对象的构造函数比较复杂,或者耗时比较长,或者是通过创建多个对象来实现。此时最好不要用new 关键字去复制,但可以通过对这些对象属性或者方法进行复制来实现,这就是原型模式的最初思想。如果涉及多个对象,我们也可以通过原型模式来实现对新对象的创建,那么首先要有一个原型模式的对象复制方法。
如:
基于已经存在的模板对象,克隆出新对象的模式
arguments[0],arguments[1],arguments[2]:参数表示模板对象
注意:这里对模板引用类型的属性实质上进行了浅复制(引用类型属性共享),当然可以根据需求自行深复制(引用类型属性复制

function prototypeExtend() {
    var F = function () { },//为实例化返回对象临时创建--缓存类
        args = arguments;
    for (var i = 0, len = args.length; i < len; i++) {
        //遍历每个模板对象中的属性
        for (var j in args[i]) {
            //将这些属性复制到缓存类原型中
            F.prototype[j] = args[i][j];
        }
    }
    return new F();
}

测试

  var penguin = prototypeExtend({
        speed: 20,
        swim: function () {
            console.log('游泳速度: ' + this.speed);
        }
    }, {
            run: function (speed) {
                console.log('奔跑速度: ' + speed);
            }
        }, {
            jump: function () {
                console.log('跳跃动作');
            }

        });
    var rabbit = prototypeExtend({

        run: function (speed) {
            console.log('奔跑速度: ' + speed);
        }
    }, {
            speed: 20,
            jump: function () {
                console.log('跳跃动作: ' + this.speed);
            }

        });


    penguin.swim();//游泳速度: 20
    penguin.run(10);//奔跑速度: 10
    penguin.jump();//跳跃动作
    rabbit.run(10);//奔跑速度: 10
    rabbit.jump();//跳跃动作: 20

话外音
多继承----只能是属性值,方法不能复制

Object.prototype.mix = function () {
    for (var i = 0, len = arguments.length; i < len; i++) {
        for (var j in arguments[i]) {
            this[j] = arguments[i][j];
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值