前言
个人推荐看一,二,三,四,八共5种模式。其他的可以学习参考使用。
一、外观模式
推荐指数:⭐️⭐️⭐️⭐️⭐️
就是我们最常用的函数了。
简单实现:
function fn(){
// do something
}
总结:没啥好说的,各位都是大佬,不敢造次。
二、构造函数模式
推荐指数:⭐️⭐️⭐️⭐️⭐️
既解决了重复实例化的问题,又解决了对象识别的问题。
简单实现:
function Person(name,age){
this.name = name;
this.age = age;
this.sayName = function(){
alert(this.name);
}
}
var p1 = new Person("小米", 22);
var p2 = new Person('小新',27);
延伸:new Person到底干了啥。拿var p1 = new Person("小米", 22)来说:
var p = {}
// 创建一个新对象p1.__proto__ = Person.prototype
// 让这个o对象的proto指向函数的原型prototypePerson.call(p1)
// this指向p1对象p1 = p
// 将p对象赋给p1
总结:比工厂模式叼,因为我们可以使用constructor和instanceof去判断去识别对象类型,而且各位可以去试试如何解决大量if,else
问题有奇效。
三、发布订阅模式
推荐指数:⭐️⭐️⭐️⭐️⭐️
定义:
在发布-订阅模式,消息的发送方,叫做发布者(publishers),消息不会直接发送给特定的接收者(订阅者)。
意思就是发布者和订阅者不知道对方的存在。需要一个第三方组件,叫做信息中介,它将订阅者和发布者串联起来。
与观察者模式不同点:
a. 和下面观察者模式不同的是,观察者是知道主体的,主体一直保持对观察者进行记录;发布者和订阅者不知道对方的存在。
b. 观察者模式大多数时候是同步的,比如当事件触发,主体就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的(使用消息队列)。
简单实现:
var pubsub = (()=>{
var topics = {};
function subscribe(topic,fn){
if(!topics[topic]){
topics[topic] = [];
}
topics[topic].push(fn);
}
function publish(topic,...args){
if(!topics[topic])
return;
for(let fn of topics[topic]){
fn(...args);
}
}
return {
subscribe,
publish
}
})()
测试代码
pubsub.subscribe('test',function(a,b){ //订阅者A订阅了test事件
console.log(a,b);
});
pubsub.publish('test','123','HH'); //123 HH(发布者B发布了test事件)
总结:订阅者A和发布者B是通过pubsub这个对象关联起来的,他们没有直接的交流。处理异步方法有奇效。
四、观察者模式
推荐指数:⭐️⭐️⭐️⭐️⭐️
比如你在打游戏,你跟对面在激战,发信号需要援助,队友可以支援,也可以不支援,你的队友属于观察者。
定义:它定义对象间 一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。由主体和观察者组成,主体负责发布事件,同时观察者通过订阅这些事件来观察该主体。主体并不知道观察者的任何事情,观察者知道主体并能注册事件的回调函数。
实现自定义事件:
class Subject{
constructor(){
this.subs = [];
}
addSub(sub){
this.subs.push(sub);
}
notify(){
this.subs.forEach(sub=> {
sub.update();
});
}
}
class Observer{
update(){
console.log('update');
}
}
// 调用事件
Event.on('customClick', function (v) {
console.log(v);
});
Event.emit('customClick', 'hello world'); // 输出 'hello world' 和 'customClick'
测试代码
let subject = new Subject();
let ob = new Observer();
//目标添加观察者了
subject.addSub(ob);
//目标发布消息调用观察者的更新方法了
subject.notify(); //update
总结:观察者模式经典案例,vue的双向绑定
。
五、工厂模式
推荐指数:⭐️⭐️⭐️
顾名思义,像工人工作一样,解决相同而重复的问题。
简单工厂模式实现:(可以针对不同水果,设置不同价格)
function fruit(name,age,sex) {
var obj = {};
obj.name = name;
obj.price = price;
obj.sayName = function(){
return this.name;
}
return obj;
}
var p1 = new Fruit("苹果",'10');
var p2 = new Fruit("梨子",'8');
console.log(p1.name); // 苹果
console.log(p2.name); // 梨子
总结:个人建议,对于简单解决多个相似问题的需求,非常好用,但是使用复杂化的工厂模式,因为其缺点(无法识别是哪个对象的实例),所以我不喜欢使用,我们的原则是写出便于理解与合作的代码。
六、原型模式
推荐指数:⭐️⭐️
每个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法,prototype就是通过调用构造函数而创建的那个对象实例的原型对象。
简单实现:
function Person(name,age){
Person.prototype.name = '小米';
}
var p1 = new Person();
总结:个人感觉难理解,没啥用。
七、混合模式
推荐指数:⭐️⭐️
就是把构造函数和原型模式结合,用的好能成为“杂交水稻之父”那么牛逼,用不好, 你懂得。
八、单例模式
推荐指数:⭐️⭐️⭐️⭐️
只能实例化一次的模式。
实现一个生成modal弹框的方法:(ps:普通方法最大的问题就是,每次点击都会生成新的dom,需要手动删除,性能非常浪费!)
var createModal = (function(){
var Modal;
return function(){
//关键点在这:判断modal是否存在不存在,实例化一次,如果存在就返回已经实例化的对象。
if(!Modal) {
Modal = document.createElement("div");
Modal.innerHTML = "弹窗内容";
Modal.style.display = 'none';
document.body.appendChild(Modal);
}
return Modal;
}
})();
document.getElementById("Id").onclick = function(){
// 点击后先创建一个div元素
var modal = createModal();
modal.style.display = "block";
}
没理解的,我写个简单demo。
var Fruit = function(name){
this.name = name;
};
// 获取实例对象
var getFruit = (function() {
var instance = null;
return function(name) {
if(!instance) {
instance = new Fruit(name);
}
return instance;
}
})();
// 测试单例模式的实例
console.log(getFruit("苹果")); // 苹果
console.log(getFruit("梨子")); // 苹果
总结:理解了吧,就是无论我调用几次,都是第一次实例化的对象。好处划分命名空间,减少全局变量,一些场景可避免多次的添加和删除。
九、模块模式
推荐指数:⭐️⭐️
有私有变量和私有方法,并能提供公共方法的模式。
简单工厂模式实现:(可以针对不同水果,设置不同价格)
function Fruit() {
this.name = "小明";
};
var application = (function(){
// 定义私有
var private = "私有";
// 定义私有函数
function A(){};
// 实例化一个对象后,返回该实例,然后为该实例增加一些公有属性和方法
var obj = new Fruit();
// 添加公有属性
obj.A = "aa";
// 添加公有方法
obj.B = function(){
return private;
}
// 返回该对象
return obj;
总结:个人建议,有了局部作用域let,const、es6 module、class类的出现,这个模式没什么用武之地了。