MVC
MVC即Model View Controller即模型 视图 控制器
- View:是这个js模块对应在HTML中的部分,就是展示给用户看的部分
- Model:可以从服务器获取数据,把数据给Controller。还要将Controller监听到的用户提交的数据上传到服务器
- Controller:调用model的数据,用来更新View。还要监听用户在View上的操作,获取用户提交的数据,传给model
Controller其实就是联系Model和View的桥梁,Controller拿到Model,然后将Model放到View里
http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html
MVVM
设计模式
前言
为什么要封装代码
写代码要又良好的封装,要搞内聚,低耦合。
- 封装好的代码,内部变量不会污染外部
- 可以作为一个模块给外部调用,外部调用者不需要如何实现,只需要会用即可
- 对外扩展开放,对修改关闭,即开闭原则。外部不能修改模块
工厂模式
工厂模式的名字就很直白,封装的模块就像一个工厂一样批量产出需要的对象,常见的工厂模式的一个特征就是调用的时候不需要用new
,而且传入的参数比较简单。但是调用次数可能比较频繁,经常需要产出不同的对象,频繁调用时不用new
也方便很多。一个工厂模式的代码结构:
1 2 3 4 5 6 7 8 9 10
| function factory(type) { switch(type) { case "type1": return new Type1(); case "type2": return new Type2(); case "type3": return new Type3(); } }
|
上述代码中,传入了type
,然后工厂根据不同的type
来创建不同的对象
实例:弹窗组件
需求:消息型弹窗,确认型弹窗,确认型弹窗,他们的颜色和内容都是不一样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function info(content,color){} function confirm(content,color){} function cancel(content,color){}
function popup(type,content,color){ switch(type){ case "info": return new info(content,color); case "confirm": return new confirm(content,color); case "cancel": return new cancel(content,color); } }
|
调用之后就可以不用使用new
了
1
| let info = popop("info",content,color);
|
改造成面向对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function popup(type, content, color) { if(this instanceof popup) { return new this[type](content, color); } else { return new popup(type, content, color); } }
popup.prototype.infoPopup = function(content, color) {} popup.prototype.confirmPopup = function(content, color) {} popup.prototype.cancelPopup = function(content, color) {}
|
封装成模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| (function(){ function popup(type, content, color) { if(this instanceof popup) { return new this[type](content, color); } else { return new popup(type, content, color); } }
popup.prototype.infoPopup = function(content, color) {} popup.prototype.confirmPopup = function(content, color) {} popup.prototype.cancelPopup = function(content, color) {} window.popup = popup; })()
let infoPopup1 = popup('infoPopup', content, color);
|
建造者模式
创建者模式是用于比较复炸的大对象构建,比如Vue
,Vue
内部包含一个功能强大,逻辑复杂的对象,在构建的时候也需要传很多参数进去,像这种需要创建的情况不多,创建的对象本身又复杂的时候就使用建造者模式。建造者模式的一般结构如下:
1 2 3 4 5 6 7 8
| function Model(){} function Mode2(){}
function Final(){ this.model1 = new Model1(); this.model2 = new Model2(); } const obj = new Final();
|
实例:
需求:写一个编辑器插件,初始化的时候需要配置大量参数,而且内部的功能很多很复杂,可以改变字体颜色和大小,也可以前进后退。
一般一个页面就只有一个编辑器,而且里面的功能可能很复杂,可能需要调整颜色,字体等。也就是说这个插件内部可能还会调用其他类,然后将他们组合起来实现功能,这就适合建造者模式。我们来分析下做这样一个编辑器需要哪些模块:
- 编辑器本身肯定需要一个类,是给外部调用的接口
- 需要一个控制参数初始化和页面渲染的类
- 需要一个控制字体的类
- 需要一个状态管理的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Editor{ constructor(){ this.initer = new HtmlInit(); this.fontController = new FontController(); this.stateController = new StateController(this.fontController); } }
class HtmlInit { initStyle(){} renderDom(){} }
class FontController { changeFontColor(){} changeFontSize(){} }
class StateController { constructor(fontController){ this.states = []; this.currentState = 0; this.fontController = fontController; } saveState(){} backState(){} forwardState(){} }
|
单例模式
定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点
1 2 3 4 5 6 7 8 9
| function Singleton(){}
Singleton.getInstance = function(){ if(this.instance){ return this.instance; } this.instance = new Singleton(); return this.instance; }
|
Singleton
的getInstance
,这个方法会检测是不是又现存的实例对象,如果又就返回,没有就新建一个
实例:
需求:一个全局的数据对象进行管理,这个对象只能有一个,如果有多个会导致数据不同步
这个需求要求全局只有一个数据存储对象,是典型的适合单例模式的场景,我们可以直接套用上面的代码模板,但是上面的代码模板获取instance
必须要调用getInstance
才行,要是某个使用者直接调用Singleton()
或者new Singleton()
就会出问题,这次我们换一种写法,让他们能够兼容Singleton()
和new Singleton()
,使用起来更加傻瓜化
1 2 3 4 5 6 7
| function store(){ if(store.instance) { return store.instance; } store.instance = this; }
|
上述代码支持使用new store()
的方式调用,我们使用了一个静态变量instance
来记录是否有进行过实例化,如果实例化了就返回这个实例,如果没有实例化说明是第一次调用,那就把this
赋给这个这个静态变量,因为是使用new
调用,这时候的this
指向的就是实例化出来的对象,并且最后会隐式的返回this
。
如果我们还想支持store()
直接调用,我们可以用前面工厂模式用过的方法,检测this
是不是当前类的实例,如果不是就帮他用new
调用就行了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function store(){ if(!(this instanceof store)){ return new store(); } if(store.instance) { return store.instance; } store.instance = this; }
let a = new store(); let b = store(); a === b
|
原型模式
原型模式最经典的应用就算JS本身,JS的原型链就算原型模式。JS中可以使用Objcet.create
指定一个对象作为原型来创建对象:
1 2 3 4 5 6 7 8
| const obj = { x: 1, func: ()=>{} }
const newObj = Object.create(obj); console.log(newObj.__proto__ === obj); console.log(newObj.x)
|
装饰者模式
指在不修改原有代码的情况下增加新功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function sleep(who) { who?console.log(who + '睡觉'):console.log('睡觉')
} Function.prototype.before = function (callback) { return (...args)=> { callback() args?this(...args):this() } } let Wash = sleep.before(function () { console.log('洗脸') }) Wash() Wash('我')
|
发布订阅模式
定义了对象间一种一对多的依赖关系,当目标对象 Subject 的状态发生改变时,所有依赖它的对象 Observer 都会得到通知。
一个目标者对象 Subject,拥有方法:添加 / 删除 / 通知 Observer;
多个观察者对象 Observer,拥有方法:接收 Subject 状态变更通知并处理;
目标对象 Subject 状态变更时,通知所有 Observer。
Subject 添加一系列 Observer, Subject 负责维护与这些 Observer 之间的联系,“你对我有兴趣,我更新就会通知你”。
作用:
- 广泛应用于异步编程中(替代了传递回调函数)
- 对象之间松散耦合的编写代码
代码实现: