### 1、单例模式
*****
* 保证一个类仅有一个实例(已经定义(内存中存在)了则直接返回,未定义则创建实例),并提供一个访问它的全局访问点。
就是说:只要创建了,就不会更改了,以后一直读取都是它。
```
function A(opt){
this.name = opt.name
}
A.prototype.funA = function (){
return this.name+' 这是单例!'
}
var func = (function (){
var instance = null;
return function (opt){
if(!instance){ // 保证只创建一个实例
instance = new A(opt)
}
return instance;
}
})()
var a = func({name:'这个模式是:'}) // 需要时创建,而不是立即
```
![](https://img.kancloud.cn/55/6a/556a5393529cca709466220ddd8f6bba_431x191.png)
简单封装一下:
```
var getInstance = function(fn) {
var instance = null;
return function(){
return instance || (instance = fn.call(this,arguments));
}
};
```
### 2、工厂模式
*****
比较好理解,通俗来说通过工厂方法替代new操作一种方式,如
```
function func (opt){
var obj = new Object();
obj.name = opt.name;
obj.fn = function(){
return obj.name+' welcome!';
}
return obj;
}
var a = func({name:'vvmily'});
a.fn() // vvmily welcome!
```
或者
```
class A {
funA(name) {
return new B(name)
}
}
class B{
constructor(name) {
this.name = name
}
}
var a = new A()
var aFn = a.funA('vvmily')
console.log(aFn.name) // vvmily
var bFn = a.funA('vvmily1')
console.log(bFn.name) // vvmily1
```
### 3、最经典之一:发布-订阅模式(观察者模式)
*****
* 一对多的关系,一:发布者,多:订阅(观察者),发布者(数据改变)发出消息并推送给订阅者执行相应的操作。
这个模式,很像一个小系统一样,observer 就是系统,使用时只关心`observer.subscribe('a',callback)`和`observer.publish('a', value)`即可。
下面举个例子说一下,有状态statusA和statusB,他们想让状态改变之后接收发布者发布的状态,故需要先订阅:
``` js
// 观察者
const observer = {
subscribes: [],
// 订阅集合
// 订阅
subscribe: function(type, fn) {
if (!this.subscribes[type]) {
this.subscribes[type] = [];
}
// 收集订阅者的处理
typeof fn === 'function' && this.subscribes[type].push(fn);
},
// 发布
publish: function() {
let type = [].shift.call(arguments); // 获取订阅者(名称)
// 多个行为
let fns = this.subscribes[type];
//发送n个通知,循环处理调用
for (var i = 0; i < fns.length; ++i) {
fns[i].apply(this, arguments);
}
}
};
// A订阅了某进度
observer.subscribe('statusA', function(status) {
console.log(status,"statusA");
});
// B订阅了某进度
observer.subscribe('statusB', function(status) {
console.log(status,"statusB");
});
// 进度结果出来了,需要发布通知,告诉已经订阅的A和B
observer.publish('statusA', 1); // 进度1
observer.publish('statusA', 2); // 进度2
```
* 补充:删除订阅`observer.remove('statusA')`
``` js
// 删除订阅
remove: function(type, fn) {
// 删除全部
if (typeof type === 'undefined') {
this.subscribes = [];
return;
}
const fns = this.subscribes[type];
// 遍历删除
for (var i = 0; i < fns.length; ++i) {
if (fns[i] === fn) {
fns.splice(i, 1);
}
}
}
}
```
### 4、经典模式之一:代理模式
* 为一个对象提供一个代用品,当操作对象时,需要经过替代品去操作源对象
* 代理模式主要有三种:保护代理、虚拟代理、缓存代理。
就是说:代理就是一个中间商的作用,交易双方不直接交涉;很经典,在框架,如Vue中大量使用。
* 保护代理,对主体加工,或者保护作用
``` js
// 主体,发送消息
function proxyScore(score) {
return score/100
}
// 代理,对数据进行过滤
function proxyScore(score) {
if(score>60){
sendMsg(msg);
}else{
// 统一处理,干点啥
return 0
}
}
proxyScore(98); // 0.98
```
* 虚拟代理,经典[防抖函数](https://www.kancloud.cn/vvmily_king/vvmily/2331774)实现
这里随手写一下吧,比如滚动则会这样使用`window.onscroll = proxyHandle`
```js
function debounce(fn, delay=300) {
let timer = null;
return function() {
const arg = arguments;
// 每次操作时,清除上次的定时器
clearTimeout(timer);
timer = null;
// 定义新的定时器,一段时间后进行操作
timer = setTimeout(function() {
fn.apply(this, arg);
}, delay);
}
};
// 代理
const proxyHandle = (function() {
return debounce((e)=>{
// 干点啥
}, 500);
})();
```
* 缓存代理,可以为一些开销大的运算结果提供暂时的缓存,提升效率
```js
// 主体
function strs() {
const arg = [].slice.call(arguments);
console.log("strs")
return arg.join('-')
}
// 代理
var proxyStrs = (function() {
let cache = [];
return function() {
let arg = [].slice.call(arguments).join('-');
if(cache.includes(arg)){
// 存在,则直接从内存中读取
return cache[arg]
}else{
cache.push(arg)
return strs.apply(this, arguments)
}
};
})();
console.log(
strs('a','b','c'),
strs('a','b','c'),
proxyStrs('a','b','c'),
proxyStrs('a','b','c')
) // strs()执行三次
```
- 首页
- 2021年
- 基础知识
- 同源策略
- 跨域
- css
- less
- scss
- reset
- 超出文本显示省略号
- 默认滚动条
- 清除浮动
- line-height与vertical-align
- box-sizing
- 动画
- 布局
- JavaScript
- 设计模式
- 深浅拷贝
- 排序
- canvas
- 防抖节流
- 获取屏幕/可视区域宽高
- 正则
- 重绘重排
- rem换算
- 手写算法
- apply、call和bind原理与实现
- this的理解-普通函数、箭头函数
- node
- nodejs
- express
- koa
- egg
- 基于nodeJS的全栈项目
- 小程序
- 常见问题
- ec-canvas之横竖屏切换重绘
- 公众号后台基本配置
- 小程序发布协议更新
- 小程序引入iconfont字体
- Uni-app
- 环境搭建
- 项目搭建
- 数据库
- MySQL数据库安装
- 数据库图形化界面常用命令行
- cmd命令行操作数据库
- Redis安装
- APP
- 控制缩放meta
- GIT
- 常用命令
- vsCode
- 常用插件
- Ajax
- axios-services
- 文章
- 如何让代码更加优雅
- 虚拟滚动
- 网站收藏
- 防抖节流之定时器清除问题
- 号称破解全网会员的脚本
- 资料笔记
- 资料笔记2
- 公司面试题
- 服务器相关
- 前端自动化部署-jenkins
- nginx.conf配置
- https添加证书
- shell基本命令
- 微型ssh-deploy前端部署插件
- webpack
- 深入理解loader
- 深入理解plugin
- webpack注意事项
- vite和webpack区别
- React
- react+antd搭建
- Vue
- vue-cli
- vue.config.js
- 面板分割左右拖动
- vvmily-admin-template
- v-if与v-for那个优先级高?
- 下载excel
- 导入excel
- Echart-China-Map
- vue-xlsx(解析excel)
- 给elementUI的el-table添加骨架
- cdn引入配置
- Vue2.x之defineProperty应用
- 彻底弄懂diff算法的key作用
- 复制模板内容
- 表格操作按钮太多
- element常用组件二次封装
- Vue3.x
- Vue3快速上手(第一天)
- Vue3.x快速上手(第二天)
- Vue3.x快速上手(第三天)
- vue3+element-plus搭建项目
- vue3
- 脚手架
- vvmily-cli
- TS
- ts笔记
- common
- Date
- utils
- axios封装
- 2022年
- HTML
- CSS基础
- JavaScript 基础
- 前端框架Vue
- 计算机网络
- 浏览器相关
- 性能优化
- js手写代码
- 前端安全
- 前端算法
- 前端构建与编译
- 操作系统
- Node.js
- 一些开放问题、智力题