設計模式真的不少很複雜,建議有興趣的看我文章最後的連接去學習,要想掌握和熟練應用到項目中絕對不是一蹴而就的,我這篇文章頂多就是一個入門級別的學習,讓你們對設計模式有個概念,我講的也很是簡單,代碼太長我本身都懶得看,因此儘可能舉簡單的例子,說實話,設計模式我啃得也很痛苦,說多了都是淚,哈哈!最後說明一下,文章並未列出23種設計模式,我只按照我以爲重要和使用多的講了上面11個,也並不是全部的模式都寫了實現代碼,後續有時間和必要的話,可能還會更新其餘的模式。javascript
用構造函數來生成對象html
// 實例共享的方法定義在原型上,實例自己的屬性定義在構造函數裏面
function Car( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
}
// 這裏注意要在原型上添加方法,而不是給原型賦值,否則就會丟失原型
Car.prototype.toString = function () {
return this.model + " has done " + this.miles + " miles";
};
// Usage:
var civic = new Car( "Honda Civic", 2009, 20000 );
var mondeo = new Car( "Ford Mondeo", 2010, 5000 );
console.log( civic.toString() );
console.log( mondeo.toString() );
複製代碼
// 簡單模擬一下jQuery的實現
class jQuery {
constructor(selector) {
let slice = Array.prototype.slice
let dom = slice.call(document.querySelectorAll(selector))
let len = dom.length? dom.length: 0
for (let i = 0; i < len; i++) {
this[i] = dom[i]
}
this.length = len
this.selector = selector
}
addClass() {
}
...
}
// $就是一個工廠
window.$ = function(selector) {
return new jQuery(selector)
}
複製代碼
class Singleton {
login() {
}
}
Singleton.getInstance = (function() {
let instance
return function() {
if(!instance) {
instance = new Singleton()
}
return instance
}
})()
let obj1 = Singleton.getInstance()
let obj2 = Singleton.getInstance()
console.log(obj1 === obj2) // true
複製代碼
let onWatch = (obj, setBind, getLogger) => {
let handler = {
get(target, property, receiver) {
getLogger(target, property);
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
setBind(value, property);
return Reflect.set(target, property, value);
}
};
return new Proxy(obj, handler);
};
let obj = { a: 1 };
let p = onWatch(
obj,
(v, property) => {
console.log(`監聽到屬性${property}改變爲${v}`);
},
(target, property) => {
console.log(`'${property}' = ${target[property]}`);
}
);
p.a = 2; // 監聽到屬性a改變
p.a; // 'a' = 2
複製代碼
class EventEmitter {
constructor() {
this._events = {}; // 維護訂閱者列表
}
// 訂閱主題
on(name, fn) {
if (name in this._events) {
// 避免重複訂閱
if(!this._events[name].find(f => f === fn)) {
this_events[name].push(fn);
}
} else {
this._events[name] = [];
this._events[name].push(fn);
}
}
// 發佈主題,相關主題的訂閱者更新
emit(name, ...arg) {
if (name in this._events) {
let events = this._events[name];
for (let i = 0; i < events.length; i++) {
events[i](...arg);
}
}
}
// 取消訂閱
off(name, fn) {
if (name in this._events) {
let index = this._events[name].findIndex(f => f === fn);
if (index > -1) {
this._events[name].splice(index, 1);
}
}
}
}
let event = new EventEmitter();
function subFn(data) {
console.log(data);
}
// 訂閱主題
event.on("vue", subFn);
// 發佈通知
event.emit("vue", "vue3.0要出來了"); // "vue3.0要出來了"
// 取消訂閱
event.off("vue", subFn);
// 再發布通知,就不會打印了
event.emit("vue", "vue3.0立刻要出來了");
複製代碼
阮一峯的ES6教程中對裝飾器講的很好很全面,你們能夠去看看,連接在此(es6.ruanyifeng.com/#docs/decor…)前端
$.each(['dudu', 'dudu', '酸奶小妹', '那個MM'], function (index, value) {
console.log(index + ': ' + value);
});
//或者
$('li').each(function (index) {
console.log(index + ': ' + $(this).text());
});
複製代碼
外觀模式不只簡化類中的接口,並且對接口與調用者也進行了解耦。外觀模式常常被認爲開發者必備,它能夠將一些複雜操做封裝起來,並建立一個簡單的接口用於調用。vue
外觀模式常常被用於JavaScript類庫裏,經過它封裝一些接口用於兼容多瀏覽器,外觀模式可讓咱們間接調用子系統,從而避免因直接訪問子系統而產生沒必要要的錯誤。java
外觀模式的優點是易於使用,並且自己也比較輕量級。但也有缺點 外觀模式被開發者連續使用時會產生必定的性能問題,由於在每次調用時都要檢測功能的可用性node
var addMyEvent = function (el, event, fn) {
if (el.addEventListener) {
el.addEventListener(event, fn, false);
} else if (el.attachEvent) {
el.attachEvent('on' + event, fn);
} else {
el['on' + event] = fn;
}
};
複製代碼
咱們如今有一個汽車管理類, 以下es6
(function() {
var carManager = {
// 獲取汽車的信息
requestInfo: function(model, id) {
return "The information for " + model + " with ID " + id + " is foobar";
},
// 購買汽車
buyVehicle: function(model, id) {
return "You have successfully purchased Item " + id + ", a " + model;
},
// 組織車展
arrangeViewing: function(model, id) {
return (
"You have successfully booked a viewing of " +
model +
" ( " +
id +
" ) "
);
}
}
})();
// 調用方法
carManager.requestInfo( "Ferrari", "14523" );
carManager.buyVehicle( "Ford Mondeo", "54323" );
carManager.arrangeViewing("Ford Escort", "34232" );
複製代碼
然而在一些狀況下,咱們並不想直接調用對象內部的方法。這樣會增長對象與對象間的依賴。如今咱們來擴展一下這個CarManager, 使其可以接受任何來自包括model和car ID 的CarManager對象的處理請求。根據命令模式的定義,咱們但願實現以下這種功能的調用:面試
CarManager.execute({ commandType: "buyVehicle", operand1: 'Ford Escort', operand2: '453543' });
複製代碼
根據這樣的需求,咱們能夠這樣實現CarManager.execute方法:算法
CarManager.execute = function (command) {
return CarManager[command.request](command.model, command.carID);
};
複製代碼
改造之後,調用就簡單多了,以下調用均可以實現vuex
CarManager.execute({ request: "arrangeViewing", model: 'Ferrari', carID: '145523' });
CarManager.execute({ request: "requestInfo", model: 'Ford Mondeo', carID: '543434' });
CarManager.execute({ request: "requestInfo", model: 'Ford Escort', carID: '543434' });
CarManager.execute({ request: "buyVehicle", model: 'Ford Escort', carID: '543434' });
複製代碼
參考資料: