工厂模式
像流水线作业,产出一样的产品。传参进去,操作的具体逻辑封装在一个方法里,最终返回一个对象。
将new操作单独封装,遇到new时,就要考虑是否用工厂模式
这个Creator就是一个工厂,里面有create函数,工厂通过create函数创建product。这样通过create已经把真正的构造函数封装起来,外部只需要知道create能生成一个实例就行。
class Product {
constructor(name) {
this.name = name;
}
init() {
console.log('init');
}
fn1() {
console.log('fn1');
}
fn2() {
console.log('fn2');
}
}
class Creator {
create(name) {
return new Product(name)
}
}
let creator = new Creator();
let p = creator.create('Sunny');
p.init();
p.fn1();
p.fn2();
单例模式
单例模式也叫单体模式,是一个将一批属性和方法组织在一起的对象,如果他可以被实例化,那么只能被实例化一次。
构造函数每次创建对象只有一个被创建。(一个类只有一个实例,并提供一个全局访问点,类似与vuex全局状态管理,提供一个接口访问)
创建单例模式的方法
1. 声明一个变量,赋值一个自运行函数
var getInstance = (function(){
function Person(_name){
this.name = _name;
}
var instance = null;
return function(_name){ //返回值为一个函数
if(instance==null){
instance = new Person(_name);
}
return instance;
}
})();
var p1 = getInstance("张三");
var p2 = getInstance("李四");
console.log(p1); //Person {name: "张三"}
console.log(p2); //Person {name: "张三"}
2. prototype原型
var Singleton = function(_name){
if(this.instance==null){
Singleton.prototype.instance = this;
}
this.name = _name;
return this.instance;
}
var p1 = new Singleton("张三");
var p2 = new Singleton("李四");
console.log(p1); //Person {name: "张三"}
console.log(p2); //Person {name: "张三"}
3. 静态变量
var SingLeton = function(_name){
if(SingLeton.instance==null){
SingLeton.instance = {name:_name};
}
return SingLeton.instance;
}
var p1 = new SingLeton("张三");
var p2 = new SingLeton("李四");
console.log(p1); //{name: "张三"}
console.log(p2); //{name: "张三"}
单例模式的使用场景有: 弹出窗口
<html>
<head>
<title>弹出窗口实例</title>
</head>
<body>
<input type="button" value="创建" id="btn1">
<input type="button" value="显示" id="btn2">
<input type="button" value="隐藏" id="btn3">
<body>
</html>
<script>
var Div = function(_text){
this.text = _text;
this.elem = null;
this.create = function(){
var div = document.createElement("div");
document.body.appendChild(div);
div.style.cssText = "width: 100px; height: 100px; background: skyblue;";
div.innerHTML = _text;
this.elem = div;
}
this.show = function(){
this.elem.style.display = "block";
}
this.hide = function(){
this.elem.style.display = "none";
}
}
//单例模式
var openWin = (function(){
var instance = null;
return function(_text){
if(instance==null){
instance = new Div(_text);
instance.create();
}
return instance;
}
})();
//创建按钮
document.getElementById("btn1").onclick = function(){
var win = openWin(parseInt(Math.random()*10));
console.log(win);
}
//显示按钮
document.getElementById("btn2").onclick = function(){
var win = openWin(parseInt(Math.random()*10));
win.show();
console.log(win);
}
//隐藏按钮
document.getElementById("btn3").onclick = function(){
var win = openWin(parseInt(Math.random()*10));
win.hide();
console.log(win);
}
</script>
适配器模式
相当于一个转换接口:解决两个软件实体间的接口不兼容问题。
var map1 = {
show: function () {
console.log('map1');
}
}
var map2 = {
display: function () {
console.log('map2');
}
}
var readMap = function (map) {
if (map.show instanceof Function) {
map.show();
}
}
// 适配器
var map2Adapter = {
show: function () {
return map2.display();
}
}
readMap(map1);
readMap(map2Adapter);
代理模式
代理是一个对象,它可以用来控制对本体对象的访问,而本体对象则负责执行所分派的那个对象的函数或者类,简单的来讲本体对象注重的去执行页面上的代码,代理则控制本地对象何时被实例化,何时被使用。
在有耦合关系的两个对象之间建立代理对象,代理对象起到类似中介的作用,比如校验,合并。
(在事件(事件委托)的时候其实就是用了代理模式,委托父元素进行监听,这样增加元素/删除元素就不用去修改监听的代码)
经典事例一:屌丝想送女神花, 条件:女神心情多变,心情好时会说thanks,不好会说getout.所以屌丝找到一个中间者监听女生的心情,心情好时通知屌丝送花
var diaosi = {
sendFlower: function (girl) {
girl.recieveFlower();
}
}
var girl = {
mood: null,
words: '',
recieveFlower: function () {
this.words = this.mood === 'good' ? 'thanks' : 'get out';
console.log(this.words)
},
changeMood: function () {
setInterval(() => {
this.mood = Math.random() - 0.5 > 0 ? 'good' : 'sad';
}, 300)
}
}
var oldDriver = {
watch: function () {
var timer = setInterval(() => {
var mood = girl.mood;
if (mood === 'good') {
diaosi.sendFlower(girl);
clearInterval(timer)
}
}, 300)
}
}
girl.changeMood();
oldDriver.watch();
事例二:图片预加载和懒加载代理。控制图片的懒加载和预加载的发生时间和过程
懒加载:针对的是全加载,把页面中的图片全加载完,增加网络请求的负担,造成请求支援浪费,这个时候就可以用到懒加载,什么时候需要什么时候再加载
预加载:针对的是完全onload了资源以后,才往dom中插入(对应的是直接设置src和直接插入dom)。容易造成加载过程中出现图片从上往下慢慢加一段段出现,加 重了浏览器的渲染负担。
var insertImg = (function () {
var result = null;
return function (id, src) {
if (result) {
return result;
}
var img = new Image();
this.setSrc = function (src) {
img.src = src;
}
document.getElementById(id).appendChild(img);
result = this;
}
})();
document.onscroll = function () {
var oTop = demo.offsetTop;
if (window.pageYOffset >= oTop) {
proxy('http://image/1.png'); // 真正需要加载的图片
}
}
var proxy = (function () {
var oImg = new insertImg('demo');
oImg.setSrc('http://image/2.png');
return function (src) {
var myImg = new Image();
myImg.onload = function () {
oImg.setSrc(src);
}
myImg.src = src;
}
})();
事例三:缓存代理
<html>
<body>
<input type="button" value="直接取值" id="btn1">
<input type="button" value="缓存取值" id="btn2">
</body>
</html>
<script>
//基本类
var DB = function(){
this.i = 10;
this.getNum = function(){
this.i++;
return this.i;
}
}
var db = new DB();
document.getElementById("btn1").onclick = function(){
alert(db.getNum());
}
//缓存代理
var Proxy = function(){
this.cache = {};
this.getNumber = function(){
if(this.cache["tmp"]==null){
this.cache["tmp"]=db.getNum();
}
return this.cache["tmp"];
}
};
var pro = new Proxy();
document.getElementById("btn2").onclick = function(){
alert(pro.getNumber());
}
</script>
发布订阅模式
观察者模式又叫发布-订阅模式,它定义了对象间的一种一对多的关系,让多个观察者对象 同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
<html>
<body>
<input type="button" value="卖家有货,发布通知" id="btn1" />
<input type="button" value="买家1,订阅" id="btn2" />
<input type="button" value="买家2,订阅" id="btn3" />
<input type="button" value="买家3,订阅" id="btn4" />
</body>
</html>
<script>
// 定义卖家,发布者
var shop = {};
// 缓存列表,存放订阅者的回调函数
shop.list = [];
// 增加订阅者
shop.listen = function(fn) {
shop.list.push(fn);
}
// 卖家发布通知
shop.trigger = function() {
for(var i = 0, l = shop.list.length; i < l; i++) {
var fn = shop.list[i];
fn();
}
}
// 商家
document.getElementById("btn1").onclick = function() {
shop.trigger();
}
// 消费者
document.getElementById("btn2").onclick = function() {
shop.listen(function() {
console.log("买家1,订阅此商品。");
});
}
document.getElementById("btn3").onclick = function() {
shop.listen(function() {
console.log("买家2,订阅此商品。");
});
}
document.getElementById("btn4").onclick = function() {
shop.listen(function() {
console.log("买家3,订阅此商品。");
btn4.style.background = "red";
});
}
</script>
策略模式
策略模式,又叫算法簇cù模式。 策略模式指的是定义一些列的算法,把他们一个个封装起来,目的就是将算法的使用与算法 的实现分离开来。
根据情况进行不一样的方案。比如想去旅游,确定自己多少钱才能决定乘坐什么交通工具
var strategies = {
rich: function () {
console.log('You can go with plane!');
},
poor: function () {
console.log('You can go with your feet!');
},
middle: function () {
console.log('You can go with train!');
}
}
var hosShoulsGo = function (money) {
return strategies[money]()
}
console.log(hosShoulsGo('rich'));
迭代器模式
提供一种按顺序访问的方法。比如forEach,通过顺序访问的模式。
var myForEach = function (arr, callBack) {
for (var i = 0, l = arr.length; i < l; i++) {
callBack(i, arr[i]);
}
}
myForEach([1, 2, 3], (item, n) => {
console.log([item, n])
});
function A(callBack) {
console.log('A');
callBack();
}
function B() {
console.log('B');
}
A(B);