1.工厂模式:
定义:不暴露创建对象的具体逻辑,而是将逻辑封装在一个函数中,这个函数被视为一个工厂
分类:简单工厂,工厂方法,抽象工厂
区别:简单工厂是将创建对象的步骤放在父类进行,工厂方法是延迟到子类中进行,它们两者都可以总结为:“根据传入的字符串来选择对应的类”,而抽象工厂则是:“用第一个字符串选择父类,再用第二个字符串选择子类”
- 实现简单工厂 (ES5):
var UserFactory = function (role) {
function Admin() {
this.name = "管理员",
this.viewPage = ['首页', '查询', '权限管理']
}
function User() {
this.name = '普通用户',
this.viewPage = ['首页', '查询']
}
switch (role) {
case 'admin':
return new Admin();
break;
case 'user':
return new User();
break;
default:
throw new Error('参数错误, 可选参数: admin、user');
}
}
var admin = UserFactory('admin');
var user = UserFactory('user');
- 实现工厂方法 (ES5):
//安全模式创建的工厂方法函数
var UserFactory = function (role) {
if (this instanceof UserFactory) {
var s = new this[role]();
return s;
} else {
return new UserFactory(role);
}
}
//工厂方法函数的原型中设置所有对象的构造函数
UserFactory.prototype = {
Admin: function () {
this.name = "管理员",
this.viewPage = ['首页', '查询', '权限管理']
},
User: function () {
this.name = '用户',
this.viewPage = ['首页', '查询']
}
}
//调用
var admin = UserFactory('Admin');
var user = UserFactory('User');
2.单例模式:
定义:保证一个类仅有一个实例,并且提供一个可以访问它的访问点
实现:用一个变量来标识实例是否已经存在,如果存在,则直接返回已经创建好的实例,反之就创建一个对象
场景:模态框、浏览器window对象,弹窗,无论点击多少次,弹窗只应该被创建一次
简单实现 (ES6):
class Singleton {
//构造函数
constructor(name) {
this.name = name;
}
//实例方法
getName() {
console.log(this.name);
}
//静态方法获取实例对象
static getInstance(name) {
if (!this.instance) {
this.instance = new Singleton(name);
}
return this.instance;
}
}
//创建静态属性作为唯一标识
Singleton.instance = null;
//验证
var a = Singleton.getInstance('a');
var b = Singleton.getInstance('b');
a.getName(); //a
b.getName(); //a
console.log(a===b);//true
3.观察者模式(发布-订阅):
定义:当一个对象的状态发生变化时,所有依赖于他的对象都将得到通知
实现:指定一个发布者,给发布者添加一个缓存列表,列表用于存放回调函数以便通知订阅者, 发布者发布消息的时候,会遍历这个缓存列表,触发里面存放的订阅者回调函数
场景:
//订阅消息
myDiv.addEventListener('click', function(){
console.log("myDiv被点击了")
});
//发布消息
myDiv.click();
简单实现 (ES6):
//发布者(售楼处)
class SalesOffices{
constructor(){
//缓存列表(售楼花名册)
this.clientList = [];
}
//订阅函数(订阅售楼消息)
listen(fn){
this.clientList.push(fn);
}
//发布函数(发布售楼消息)
trigger(){
//遍历花名册,给他们发消息
for(var i=0;i<this.clientList.length;i++){
var fn = this.clientList[i];
fn.apply(this,arguments);
}
}
}
//实例化
var salesOffices = new SalesOffices();
//小明订阅售楼消息
salesOffices.listen(function(price){
console.log("小明" + price);
});
//小红订阅售楼消息
salesOffices.listen(function(price){
console.log("小红" + price);
});
//售楼处发布售楼消息
salesOffices.trigger("你好,今天的房价为2万一平!");
//打印结果:
小明你好,今天的房价为2万一平!
小红你好,今天的房价为2万一平!
4.构造函数模式:
function Person(name , age){
this.name = name;
this.age = age;
this.sayName = function(){
console.log(this.name)
}
}
var person1 = new Person('ccc', 18)
var person2 = new Person('www', 18)
person1.sayName() // --> 'ccc'
**person1 和person2 分别保存着Person的一个不同的实例。这两个对象都有一个constructor(构造函数)属性指向Person。这正是构造函数模式胜过工厂模式的地方。**如下:
console.log(person1 instanceof Person) // --> true
console.log(person1 instanceof Object) // --> true
console.log(person2 instanceof Person) // --> true
console.log(person2 instanceof Object) // --> true
构造函数模式与工厂模式的区别:
- 没有显式的创建对象
- 直接将属性和方法赋给了this对象
- 没有return 语句
要创建Person的新实例,必须使用new操作符。以这种方式调用构造函数实际上会经历一下4个步骤:
- 创建一个新对象
- 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回新对象
5.代理模式:
代理模式的定义:为一个对象提供一个代用品或占位符,以便控制对它的访问。
常用的虚拟代理形式:某一个花销很大的操作,可以通过虚拟代理的方式延迟到这种需要它的时候才去创建(例:使用虚拟代理实现图片懒加载)
图片懒加载的方式:先通过一张loading图占位,然后通过异步的方式加载图片,等图片加载好了再把完成的图片加载到img标签里面。
var imgFunc = (function() {
var imgNode = document.createElement('img');
document.body.appendChild(imgNode); //是真正挂在到页面上的图片,但平没有设置src
return {
setSrc: function(src) {
imgNode.src = src;
}
}
})();
var proxyImage = (function() {
var img = new Image(); // 此img 对象用于加载真实图片
img.onload = function() {
// 加载好后将图片链接赋值到挂载图片的src
imgFunc.setSrc(this.src);
}
return {
setSrc: function(src) {
imgFunc.setSrc('./loading,gif'); // 先让挂载图片显示loading
img.src = src; // 让img去加载真实的图片
}
}
})();
proxyImage.setSrc('./pic.png');