原型模式(Prototype)
用原型实例指向创建对象的类,使用于创建新的对象的类共享原型对象的属性以及方法。
需求:创建一个焦点轮播图
<p>自动切换</p>
<img id="carousel1" class="carousel" src=""/>
<p>监听滚动切换</p>
<img id="carousel2" class="carousel" src=""/>
// 图片轮播类
var Carousel = function (imgList, container) {
// 轮播索引
this.index = 0;
// 轮播图片数组
this.imgList = imgList;
// 轮播图片容器
this.container = container;
// 创建轮播图片
this.create = function () {
let img = document.getElementById(this.container);
img.src = this.imgList[this.index];
};
// 切换下一张图片
this.change = function () {
const that = this;
setInterval(function () {
let img = document.getElementById(that.container);
that.index++;
if (that.index > that.imgList.length - 1) {
that.index = 0;
}
console.log(`%c【${container}】 ---> ${that.index}`, 'background-color: pink; color: black;');
img.src = that.imgList[that.index];
}, 2000)
};
};
默认的轮播
let imgList = [ 'https://dummyimage.com/500x300/f00/fff&text=00', 'https://dummyimage.com/500x300/0f0/fff&text=01', 'https://dummyimage.com/500x300/00f/fff&text=02', 'https://dummyimage.com/500x300/ff0/fff&text=03', 'https://dummyimage.com/500x300/0ff/fff&text=04', ]; // 实例化轮播图类 - 自动切换类 let carousel = new Carousel(imgList, 'carousel1'); carousel.create(); carousel.change();
重写的轮播形式 (监听滚动切换轮播)
// 实例化轮播图类 - 上下滑动切换类 let SlideCarousel = function (imgList, container) { const that = this; // 构造函数继承图片轮播类 Carousel.call(that, imgList, container); // 重写继承的切换下一张图片方法 that.change = function () { let img = document.getElementById(that.container); // 监听滚动 img.addEventListener('wheel', function (e) { // 向上滚动 if (e.wheelDelta > 0) { that.index++; if (that.index > that.imgList.length - 1) { that.index = 0; } } // 向下滚动 else { that.index--; if (that.index < 0) { that.index = that.imgList.length - 1; } } console.log(`%c【${container}】 ---> ${that.index}`, 'background-color: yellow; color: black;'); img.src = that.imgList[that.index]; }); } }; // 实例化轮播图类 - 上下滑动切换类 let slideCarousel = new SlideCarousel(imgList, 'carousel2'); slideCarousel.create(); slideCarousel.change();
- ⚠
缺点:
- 将
属性
和方法
都写在基类Carousel
的构造函数里面,那么每次子类继承都要创建一次父类,假如父类的构造函数中创建时存在很多耗时逻辑,或者每次初始化都做一些重复性工作,这样的性能消耗很大。- 比如:
this.create = ···
和this.change = ···
就属于消耗性能的逻辑
- 比如:
- 将
【原型模式】优化上述代码:
- ⚠
优化:
- 为了提高性能,我们需要有一种
共享机制
,这样每当创建基类时,对于每次创建的一些简单而又差异化的属性
我们可以放在构造函数中
,而我们将一些消耗资源比较大的方法
放在基类的原型
中,这样就会避免很多不必要的消耗
,这也就是原型模式
的一个雏形。
- 为了提高性能,我们需要有一种
默认的轮播
// 图片轮播类 var Carousel = function (imgList, container) { // 轮播索引 this.index = 0; // 轮播图片数组 this.imgList = imgList; // 轮播图片容器 this.container = container; }; Carousel.prototype = { // 创建轮播图片 create: function () { let img = document.getElementById(this.container); img.src = this.imgList[this.index]; }, // 切换下一张图片 change: function () { const that = this; setInterval(function () { let img = document.getElementById(that.container); that.index++; if (that.index > that.imgList.length - 1) { that.index = 0; } img.src = that.imgList[that.index]; }, 2000) } }; let imgList = [ 'https://dummyimage.com/500x300/f00/fff&text=00', 'https://dummyimage.com/500x300/0f0/fff&text=01', 'https://dummyimage.com/500x300/00f/fff&text=02', 'https://dummyimage.com/500x300/ff0/fff&text=03', 'https://dummyimage.com/500x300/0ff/fff&text=04', ]; // 实例化轮播图类 - 自动切换类 let carousel = new Carousel(imgList, 'carousel1'); carousel.create(); carousel.change();
重写的轮播形式 (监听滚动切换轮播)
// 实例化轮播图类 - 上下滑动切换类 let SlideCarousel = function (imgList, container) { // 构造函数继承图片轮播类 Carousel.call(this, imgList, container); }; SlideCarousel.prototype = new Carousel(); // 重写继承的切换下一张图片方法 SlideCarousel.prototype.change = function () { const that = this; let img = document.getElementById(that.container); // 监听滚动 img.addEventListener('wheel', function (e) { // 向上滚动 if (e.wheelDelta > 0) { that.index++; if (that.index > that.imgList.length - 1) { that.index = 0; } } // 向下滚动 else { that.index--; if (that.index < 0) { that.index = that.imgList.length - 1; } } img.src = that.imgList[that.index]; }); }; // 实例化轮播图类 - 上下滑动切换类 let slideCarousel = new SlideCarousel(imgList, 'carousel2'); slideCarousel.create(); slideCarousel.change();
原型模式的特点:
原型模式对继承他的子类都可以访问其上的属性和方法,包括杜父类拓展的方法
// 比如:
// ···Code
// 父类上拓展的方法
Carousel.prototype.getImgListCount = function () {
console.log(this.imgList.length);
};
// 子类上拓展的方法
SlideCarousel.prototype.getContainer = function () {
console.log(this.container);
};
// 子类访问父类上拓展的方法
slideCarousel.getImgListCount(); // 5
// 子类访问自己类上拓展的方法
slideCarousel.getContainer(); // carousel2
原型继承
比如现在没有人的基类,只有人的一些特性类,比如游泳、跑步、唱歌、跳舞等等,那么就可以通过以下方法创造出一个
人的实例
来
function prototypeExtend(...args) {
// 缓存类,为实例化返回对象临时创建
const F = function () {
};
for (let i = 0; i < args.length; i++) {
// 遍历每个模板对象中的属性
for (let key in args[i]) {
// 将这些属性复制到缓存类原型中
F.prototype[key] = args[i][key];
}
}
// 返回缓存类的一个实例
return new F();
}
let Swim = function (speed) {
this.speed = speed;
this.swim = function () {
console.log('游泳速度 ' + this.speed);
};
};
let Run = function () {
this.run = function (speed) {
console.log('跑步速度 ' + speed);
};
};
let Jump = function () {
this.jump = function () {
console.log('跳跃动作 ');
};
};
let person = prototypeExtend(new Swim(20), new Run(), new Jump());
person.run(10); // 跑步速度 10
person.swim(); // 跑步速度 20
/**
* F {
* [[Prototype]]: {
* jump: ƒ (),
* run: ƒ (speed),
* speed: 20,
* swim: ƒ (),
* constructor: ƒ ()
* [[Prototype]]: Object
* }
* }
*/
console.log(person);