设计者模式
1. 单例模式:每个new出来的实例都需要有一个相同的方法,但是这时候如果 每个实例都新建一个这种方法,太占据内存也太慢,所以在这里有一个重要的判断:如果有实例,则返回实例;如果没有实例,则创建实例,并且返回实例。
例:
class CreateUser { static shareInstance(){ if(!CreateUser.ins){ CreateUser.ins = new CreateUser('aa') } return CreateUser.ins; } constructor(name) { this.name = name; this.getName(); } getName() { return this.name; } } let c1 = CreateUser.shareInstance() let c2 = CreateUser.shareInstance() console.log(c1==c2)
2. 组合模式:组合模式中基本对象和组合对象被一致对待;无须关心对象有多少层, 调用时只需在根部进行调用;类似DOM树
例:
const MacroCommand = function() { return { lists: [], add: function(task) { this.lists.push(task) }, excute: function() { // 组合对象调用这里的 excute, for (let i = 0; i < this.lists.length; i++) { this.lists[i].excute() } }, } } const command1 = MacroCommand() // 命令1 command1.add({ excute: () => console.log('吃饭') // }) const command2 = MacroCommand() // 命令2 command2.add({ excute: () => console.log('唱歌') }) command2.add({ excute: () => console.log('画画') }) const command3 = MacroCommand() //命令3 command3.add({ excute: () => console.log('下棋') }) command3.add({ excute: () => console.log('玩游戏') }) const macroCommand = MacroCommand()//组合对象 macroCommand.add(command1) macroCommand.add(command2) macroCommand.add(command3) macroCommand.excute() // 吃饭 // 唱歌 //画画 // 下棋 // 玩游戏
3. 观察者模式:类似于事件监听, 观察者只要订阅了被观察者的事件,那么当被观察者的状态改变时,被观察者会主动去通知观察者,而无需关心观察者得到事件后要去做什么,实际程序中可能是执行订阅者的回调函数
例:
var obj = { data: { list: [] }, } // defineProperty 可以观察 obj对象 的list 属性的使用 Object.defineProperty(obj, 'list', { get() { console.log('获取了list 属性') console.log(this.data['list']) return this.data['list'] }, set(val) { console.log('值被更改了') this.data['list'] = val } }) // 获取了list属性,那么get 方法就会被调用 console.log(obj.list) // 设置了list属性set 方法就会被调用 obj.list = ['a', 'b']
4. 工厂模式: 去做同样的事情,实现同样的效果,批量生产
例:
// 文本工厂 class Text { constructor(text) { this.text = text } insert(where) { const txt = document.createTextNode(this.text) where.appendChild(txt) } } // 链接工厂 class Link { constructor(url) { this.url = url } insert(where) { const link = document.createElement('a') link.href = this.url link.appendChild(document.createTextNode(this.url)) where.appendChild(link) } }
5. 抽象的工厂模式:先标记好模式,然后下面引用,但是里面什么都没有
class DomFactory { constructor() { } // 各流水线 insert() { } }
6. 策略模式:策略类部分和环境类部分
①策略类:写出好几种策略,类似于planA,planB….
例:
var levelOBJ = { "A": function (money) { return money * 4; }, "B": function (money) { return money * 3; }, "C": function (money) { return money * 2; } }; /*环境类*/ var calculateBouns = function (level, money) { return levelOBJ[level](money); }; console.log(calculateBouns('A', 10000)); // 40000
②环境类:运行的环境
7. 代理模式:经典例子:刚打开页面的时候加载个loading图片占位,等图片加载过来后再显示该图片,提前占坑
例:
const MyImage = function (parent) { const imgNode = document.createElement('img') parent.appendChild(imgNode) // 提供一个方法 ,让外部也能修改 图片的src属性 this.setSrc = function(src){ imgNode.src = src } } // 直接添加图片 ,如果图片比较大,可能加载的比较慢,导致网页上的img一开始显示不出来 let myImage = new MyImage(document.body) // 写个代理 提供 预加载功能 const ProxyImage = function (myImage) { // 创建image对象 const img = new Image() img.on // 监听img对象的 onload 方法 img.onload = function () { // http 图片加载完毕后才会执行 // 模拟网络很慢的情况 setTimeout(()=>{ myImage.setSrc(this.src) },2000) } this.setSrc =function (src) { // 加载时候先不加载大图,先加载一张小图(浏览器已经下载过的) myImage.setSrc('loading.gif') // 本地 loading 图片 img.src = src } } // let proxyImage = new ProxyImage(myImage) proxyImage.setSrc('https://www.baidu.com/img/bd_logo1.png?where=super')
8. 适配器模式:类似于把obj对象转为数组,这时候如果是大量的操作怕出意外,就可以运用这种模式,就相当于有个中介转一下
例:
// 老接口 const zhejiangCityOld = function () { return [{ name: 'hangzhou', id: 11, }, { name: 'jinhua', id: 12 } ] } console.log(zhejiangCityOld()) // 新接口希望是下面形式 // { // hangzhou: 11, // jinhua:12 // } // 这时候就可采用适配者模式 const adaptor = function (oldCity) { console.log(oldCity) const obj = {} for (let city of oldCity) { obj[city.name] = city.id } return obj } let oldData = zhejiangCityOld(); //把老数据放在适配器中产生新数据 console.log(adaptor(oldData))
既然看了这么多设计者模式,接下来也可以了解一下hash,它在我们的应用中也很重要:
1.Hash:传统的网页根据用户访问的不同地址,浏览器从服务器获取对应页面的内容展示给用户,这样造成服务器压力比较大,用户访问比较慢,在这种场景下,出现了单页应用。
2. Hashchange:想要用hash就要监听到hash什么时候改变,这时候就需要用hashchange来监听