### 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:'這個模式是:'}) // 需要時創建,而不是立即
```

簡單封裝一下:
```
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
```
* 虛擬代理,經典[防抖函數](http://www.hmoore.net/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
- 一些開放問題、智力題